mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-21 03:55:06 +00:00
bcm27xx: update 6.1 patches to latest version
Add support for BCM2712 (Raspberry Pi 5).
3bb5880ab3
Patches were generated from the diff between linux kernel branch linux-6.1.y
and rpi-6.1.y from raspberry pi kernel source:
- git format-patch linux-6.1.y...rpi-6.1.y
Build system: x86_64
Build-tested: bcm2708, bcm2709, bcm2710, bcm2711
Run-tested: bcm2710/RPi3B, bcm2711/RPi4B
Signed-off-by: Marty Jones <mj8263788@gmail.com>
[Remove applied and reverted patches, squash patches and config commits]
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
This commit is contained in:
parent
65f599223d
commit
2e715fb4fc
@ -30,7 +30,6 @@ CONFIG_ARM_UNWIND=y
|
||||
CONFIG_AUTO_ZRELADDR=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2711_THERMAL is not set
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_FAST_MEMCPY=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
@ -151,7 +150,6 @@ CONFIG_FB_CFB_COPYAREA=y
|
||||
CONFIG_FB_CFB_FILLRECT=y
|
||||
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
CONFIG_FB_CMDLINE=y
|
||||
# CONFIG_FB_RPISENSE is not set
|
||||
CONFIG_FB_SIMPLE=y
|
||||
CONFIG_FIQ=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
@ -239,8 +237,6 @@ CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
|
||||
CONFIG_MIGRATION=y
|
||||
@ -266,6 +262,7 @@ CONFIG_NO_HZ=y
|
||||
CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_ADDRESS=y
|
||||
CONFIG_OF_CONFIGFS=y
|
||||
@ -296,7 +293,6 @@ CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PREEMPT_NONE_BUILD=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
@ -306,6 +302,7 @@ CONFIG_PWM_BCM2835=y
|
||||
CONFIG_PWM_SYSFS=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_GPIOMEM=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
|
@ -39,7 +39,6 @@ CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUTO_ZRELADDR=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
CONFIG_BCM2711_THERMAL=y
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
@ -186,7 +185,6 @@ CONFIG_FB_CFB_COPYAREA=y
|
||||
CONFIG_FB_CFB_FILLRECT=y
|
||||
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
CONFIG_FB_CMDLINE=y
|
||||
# CONFIG_FB_RPISENSE is not set
|
||||
CONFIG_FB_SIMPLE=y
|
||||
CONFIG_FIQ=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
@ -297,8 +295,6 @@ CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MICROCHIP_PHY=y
|
||||
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
|
||||
@ -332,6 +328,7 @@ CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_ADDRESS=y
|
||||
CONFIG_OF_CONFIGFS=y
|
||||
@ -374,7 +371,6 @@ CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PPS=y
|
||||
CONFIG_PREEMPT_NONE_BUILD=y
|
||||
@ -387,6 +383,7 @@ CONFIG_PWM_SYSFS=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_GPIOMEM=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
|
@ -60,7 +60,6 @@ CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2711_THERMAL is not set
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
@ -152,7 +151,6 @@ CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
@ -161,8 +159,6 @@ CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA256_ARM64=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_SHA512_ARM64=y
|
||||
# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
|
||||
# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
@ -195,7 +191,6 @@ CONFIG_FB_CFB_COPYAREA=y
|
||||
CONFIG_FB_CFB_FILLRECT=y
|
||||
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
CONFIG_FB_CMDLINE=y
|
||||
# CONFIG_FB_RPISENSE is not set
|
||||
CONFIG_FB_SIMPLE=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
@ -299,8 +294,6 @@ CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MICROCHIP_PHY=y
|
||||
CONFIG_MIGRATION=y
|
||||
@ -332,6 +325,7 @@ CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_ADDRESS=y
|
||||
CONFIG_OF_CONFIGFS=y
|
||||
@ -368,7 +362,6 @@ CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
|
||||
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
@ -382,6 +375,7 @@ CONFIG_QUEUED_RWLOCKS=y
|
||||
CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_GPIOMEM=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
|
@ -54,7 +54,6 @@ CONFIG_ASSOCIATIVE_ARRAY=y
|
||||
CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
CONFIG_BCM2711_THERMAL=y
|
||||
CONFIG_BCM2835_DEVGPIOMEM=y
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
CONFIG_BCM2835_POWER=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
@ -150,7 +149,6 @@ CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_SHA256=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
# CONFIG_CRYPTO_POLYVAL_ARM64_CE is not set
|
||||
CONFIG_CRYPTO_RNG=y
|
||||
CONFIG_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_RNG_DEFAULT=y
|
||||
@ -159,8 +157,6 @@ CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA256_ARM64=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_SHA512_ARM64=y
|
||||
# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
|
||||
# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
@ -194,7 +190,6 @@ CONFIG_FB_CFB_COPYAREA=y
|
||||
CONFIG_FB_CFB_FILLRECT=y
|
||||
CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
CONFIG_FB_CMDLINE=y
|
||||
# CONFIG_FB_RPISENSE is not set
|
||||
CONFIG_FB_SIMPLE=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FIX_EARLYCON_MEM=y
|
||||
@ -300,8 +295,6 @@ CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MEMFD_CREATE=y
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_CORE=y
|
||||
# CONFIG_MFD_RASPBERRYPI_POE_HAT is not set
|
||||
# CONFIG_MFD_RPISENSE_CORE is not set
|
||||
CONFIG_MFD_SYSCON=y
|
||||
CONFIG_MIGRATION=y
|
||||
CONFIG_MMC=y
|
||||
@ -333,6 +326,7 @@ CONFIG_NO_HZ_COMMON=y
|
||||
CONFIG_NO_HZ_IDLE=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_ADDRESS=y
|
||||
CONFIG_OF_CONFIGFS=y
|
||||
@ -372,7 +366,6 @@ CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
|
||||
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
@ -389,6 +382,7 @@ CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RAS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_GPIOMEM=y
|
||||
CONFIG_RASPBERRYPI_POWER=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_RAVE_SP_CORE is not set
|
||||
|
@ -1,41 +0,0 @@
|
||||
From dffb648dffeab7246040a30b7d1669387d1e767e Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 25 Apr 2023 11:49:41 +0100
|
||||
Subject: [PATCH] Bluetooth: hci_sync: Add fallback-bd-address prop
|
||||
|
||||
The kernel Bluetooth framework understands that devices may not
|
||||
be programmed with valid Bluetooth addresses. It also has the ability
|
||||
to override a Bluetooth address with the value of the local-bd-address
|
||||
DT property, but it ignores the validity of the existing address when
|
||||
doing so.
|
||||
|
||||
Add a new boolean property, fallback-bd-address, which indicates that
|
||||
the given local-bd-address property should only be used if the device
|
||||
does not already have a valid BDADDR.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
net/bluetooth/hci_sync.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/net/bluetooth/hci_sync.c
|
||||
+++ b/net/bluetooth/hci_sync.c
|
||||
@@ -4630,6 +4630,7 @@ static const struct {
|
||||
*/
|
||||
static int hci_dev_setup_sync(struct hci_dev *hdev)
|
||||
{
|
||||
+ struct fwnode_handle *fwnode = dev_fwnode(hdev->dev.parent);
|
||||
int ret = 0;
|
||||
bool invalid_bdaddr;
|
||||
size_t i;
|
||||
@@ -4658,7 +4659,9 @@ static int hci_dev_setup_sync(struct hci
|
||||
|
||||
if (!ret) {
|
||||
if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) &&
|
||||
- !bacmp(&hdev->public_addr, BDADDR_ANY))
|
||||
+ !bacmp(&hdev->public_addr, BDADDR_ANY) &&
|
||||
+ (invalid_bdaddr ||
|
||||
+ !fwnode_property_present(fwnode, "fallback-bd-address")))
|
||||
hci_dev_get_bd_addr_from_property(hdev);
|
||||
|
||||
if ((invalid_bdaddr ||
|
@ -0,0 +1,306 @@
|
||||
From 3ad8e28669e0058e3cec482a47215e50e33f2574 Mon Sep 17 00:00:00 2001
|
||||
From: Vinay Varma <varmavinaym@gmail.com>
|
||||
Date: Sun, 11 Jun 2023 23:45:03 +0800
|
||||
Subject: [PATCH] media: i2c: imx219: fix binning and rate_factor for 480p and
|
||||
1232p
|
||||
|
||||
At a high FPS with RAW10, there is frame corruption for 480p because the
|
||||
rate_factor of 2 is used with the normal 2x2 bining [1]. This commit
|
||||
ties the rate_factor to the selected binning mode. For the 480p mode,
|
||||
analog 2x2 binning mode with a rate_factor of 2 is always used. For the
|
||||
1232p mode the normal 2x2 binning mode is used for RAW10 while analog
|
||||
2x2 binning mode is used for RAW8.
|
||||
|
||||
[1] https://github.com/raspberrypi/linux/issues/5493
|
||||
|
||||
Signed-off-by: Vinay Varma <varmavinaym@gmail.com>
|
||||
---
|
||||
drivers/media/i2c/imx219.c | 143 ++++++++++++++++++++++++++-----------
|
||||
1 file changed, 100 insertions(+), 43 deletions(-)
|
||||
|
||||
--- a/drivers/media/i2c/imx219.c
|
||||
+++ b/drivers/media/i2c/imx219.c
|
||||
@@ -136,6 +136,18 @@ enum pad_types {
|
||||
NUM_PADS
|
||||
};
|
||||
|
||||
+enum binning_mode {
|
||||
+ BINNING_NONE,
|
||||
+ BINNING_DIGITAL_2x2,
|
||||
+ BINNING_ANALOG_2x2,
|
||||
+};
|
||||
+
|
||||
+enum binning_bit_depths {
|
||||
+ BINNING_IDX_8_BIT,
|
||||
+ BINNING_IDX_10_BIT,
|
||||
+ BINNING_IDX_MAX
|
||||
+};
|
||||
+
|
||||
struct imx219_reg {
|
||||
u16 address;
|
||||
u8 val;
|
||||
@@ -162,11 +174,8 @@ struct imx219_mode {
|
||||
/* Default register values */
|
||||
struct imx219_reg_list reg_list;
|
||||
|
||||
- /* 2x2 binning is used */
|
||||
- bool binning;
|
||||
-
|
||||
- /* Relative pixel clock rate factor for the mode. */
|
||||
- unsigned int rate_factor;
|
||||
+ /* binning mode based on format code */
|
||||
+ enum binning_mode binning[BINNING_IDX_MAX];
|
||||
};
|
||||
|
||||
static const struct imx219_reg imx219_common_regs[] = {
|
||||
@@ -404,8 +413,10 @@ static const struct imx219_mode supporte
|
||||
.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
|
||||
.regs = mode_3280x2464_regs,
|
||||
},
|
||||
- .binning = false,
|
||||
- .rate_factor = 1,
|
||||
+ .binning = {
|
||||
+ [BINNING_IDX_8_BIT] = BINNING_NONE,
|
||||
+ [BINNING_IDX_10_BIT] = BINNING_NONE,
|
||||
+ },
|
||||
},
|
||||
{
|
||||
/* 1080P 30fps cropped */
|
||||
@@ -422,8 +433,10 @@ static const struct imx219_mode supporte
|
||||
.num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
|
||||
.regs = mode_1920_1080_regs,
|
||||
},
|
||||
- .binning = false,
|
||||
- .rate_factor = 1,
|
||||
+ .binning = {
|
||||
+ [BINNING_IDX_8_BIT] = BINNING_NONE,
|
||||
+ [BINNING_IDX_10_BIT] = BINNING_NONE,
|
||||
+ },
|
||||
},
|
||||
{
|
||||
/* 2x2 binned 30fps mode */
|
||||
@@ -440,8 +453,10 @@ static const struct imx219_mode supporte
|
||||
.num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
|
||||
.regs = mode_1640_1232_regs,
|
||||
},
|
||||
- .binning = true,
|
||||
- .rate_factor = 1,
|
||||
+ .binning = {
|
||||
+ [BINNING_IDX_8_BIT] = BINNING_ANALOG_2x2,
|
||||
+ [BINNING_IDX_10_BIT] = BINNING_DIGITAL_2x2,
|
||||
+ },
|
||||
},
|
||||
{
|
||||
/* 640x480 30fps mode */
|
||||
@@ -458,12 +473,10 @@ static const struct imx219_mode supporte
|
||||
.num_of_regs = ARRAY_SIZE(mode_640_480_regs),
|
||||
.regs = mode_640_480_regs,
|
||||
},
|
||||
- .binning = true,
|
||||
- /*
|
||||
- * This mode uses a special 2x2 binning that doubles the
|
||||
- * internal pixel clock rate.
|
||||
- */
|
||||
- .rate_factor = 2,
|
||||
+ .binning = {
|
||||
+ [BINNING_IDX_8_BIT] = BINNING_ANALOG_2x2,
|
||||
+ [BINNING_IDX_10_BIT] = BINNING_ANALOG_2x2,
|
||||
+ },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -652,12 +665,51 @@ static int imx219_open(struct v4l2_subde
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int imx219_resolve_binning(struct imx219 *imx219,
|
||||
+ enum binning_mode *binning)
|
||||
+{
|
||||
+ switch (imx219->fmt.code) {
|
||||
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
|
||||
+ *binning = imx219->mode->binning[BINNING_IDX_8_BIT];
|
||||
+ return 0;
|
||||
+
|
||||
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
|
||||
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
|
||||
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
|
||||
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
|
||||
+ *binning = imx219->mode->binning[BINNING_IDX_10_BIT];
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int imx219_get_rate_factor(struct imx219 *imx219)
|
||||
+{
|
||||
+ enum binning_mode binning = BINNING_NONE;
|
||||
+ int ret = imx219_resolve_binning(imx219, &binning);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ switch (binning) {
|
||||
+ case BINNING_NONE:
|
||||
+ case BINNING_DIGITAL_2x2:
|
||||
+ return 1;
|
||||
+ case BINNING_ANALOG_2x2:
|
||||
+ return 2;
|
||||
+ }
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct imx219 *imx219 =
|
||||
container_of(ctrl->handler, struct imx219, ctrl_handler);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
|
||||
int ret;
|
||||
+ int rate_factor;
|
||||
|
||||
if (ctrl->id == V4L2_CID_VBLANK) {
|
||||
int exposure_max, exposure_def;
|
||||
@@ -679,6 +731,10 @@ static int imx219_set_ctrl(struct v4l2_c
|
||||
if (pm_runtime_get_if_in_use(&client->dev) == 0)
|
||||
return 0;
|
||||
|
||||
+ rate_factor = imx219_get_rate_factor(imx219);
|
||||
+ if (rate_factor < 0)
|
||||
+ return rate_factor;
|
||||
+
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_ANALOGUE_GAIN:
|
||||
ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
|
||||
@@ -687,7 +743,7 @@ static int imx219_set_ctrl(struct v4l2_c
|
||||
case V4L2_CID_EXPOSURE:
|
||||
ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
|
||||
IMX219_REG_VALUE_16BIT,
|
||||
- ctrl->val / imx219->mode->rate_factor);
|
||||
+ ctrl->val / rate_factor);
|
||||
break;
|
||||
case V4L2_CID_DIGITAL_GAIN:
|
||||
ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
|
||||
@@ -708,7 +764,7 @@ static int imx219_set_ctrl(struct v4l2_c
|
||||
ret = imx219_write_reg(imx219, IMX219_REG_VTS,
|
||||
IMX219_REG_VALUE_16BIT,
|
||||
(imx219->mode->height + ctrl->val) /
|
||||
- imx219->mode->rate_factor);
|
||||
+ rate_factor);
|
||||
break;
|
||||
case V4L2_CID_HBLANK:
|
||||
ret = imx219_write_reg(imx219, IMX219_REG_HTS,
|
||||
@@ -890,7 +946,7 @@ static int imx219_set_pad_format(struct
|
||||
struct imx219 *imx219 = to_imx219(sd);
|
||||
const struct imx219_mode *mode;
|
||||
struct v4l2_mbus_framefmt *framefmt;
|
||||
- int exposure_max, exposure_def, hblank, pixel_rate;
|
||||
+ int exposure_max, exposure_def, hblank, pixel_rate, rate_factor;
|
||||
unsigned int i;
|
||||
|
||||
if (fmt->pad >= NUM_PADS)
|
||||
@@ -924,6 +980,9 @@ static int imx219_set_pad_format(struct
|
||||
|
||||
imx219->fmt = fmt->format;
|
||||
imx219->mode = mode;
|
||||
+ rate_factor = imx219_get_rate_factor(imx219);
|
||||
+ if (rate_factor < 0)
|
||||
+ return rate_factor;
|
||||
/* Update limits and set FPS to default */
|
||||
__v4l2_ctrl_modify_range(imx219->vblank,
|
||||
IMX219_VBLANK_MIN,
|
||||
@@ -957,8 +1016,7 @@ static int imx219_set_pad_format(struct
|
||||
__v4l2_ctrl_s_ctrl(imx219->hblank, hblank);
|
||||
|
||||
/* Scale the pixel rate based on the mode specific factor */
|
||||
- pixel_rate =
|
||||
- IMX219_PIXEL_RATE * imx219->mode->rate_factor;
|
||||
+ pixel_rate = IMX219_PIXEL_RATE * rate_factor;
|
||||
__v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate,
|
||||
pixel_rate, 1, pixel_rate);
|
||||
}
|
||||
@@ -1001,30 +1059,25 @@ static int imx219_set_framefmt(struct im
|
||||
|
||||
static int imx219_set_binning(struct imx219 *imx219)
|
||||
{
|
||||
- if (!imx219->mode->binning) {
|
||||
+ enum binning_mode binning = BINNING_NONE;
|
||||
+ int ret = imx219_resolve_binning(imx219, &binning);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ switch (binning) {
|
||||
+ case BINNING_NONE:
|
||||
return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
|
||||
IMX219_REG_VALUE_16BIT,
|
||||
IMX219_BINNING_NONE);
|
||||
- }
|
||||
-
|
||||
- switch (imx219->fmt.code) {
|
||||
- case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||
- case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||
- case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||
- case MEDIA_BUS_FMT_SBGGR8_1X8:
|
||||
+ case BINNING_DIGITAL_2x2:
|
||||
return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
|
||||
IMX219_REG_VALUE_16BIT,
|
||||
- IMX219_BINNING_2X2_ANALOG);
|
||||
-
|
||||
- case MEDIA_BUS_FMT_SRGGB10_1X10:
|
||||
- case MEDIA_BUS_FMT_SGRBG10_1X10:
|
||||
- case MEDIA_BUS_FMT_SGBRG10_1X10:
|
||||
- case MEDIA_BUS_FMT_SBGGR10_1X10:
|
||||
+ IMX219_BINNING_2X2);
|
||||
+ case BINNING_ANALOG_2x2:
|
||||
return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE,
|
||||
IMX219_REG_VALUE_16BIT,
|
||||
- IMX219_BINNING_2X2);
|
||||
+ IMX219_BINNING_2X2_ANALOG);
|
||||
}
|
||||
-
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1342,7 +1395,7 @@ static int imx219_init_controls(struct i
|
||||
struct v4l2_ctrl_handler *ctrl_hdlr;
|
||||
unsigned int height = imx219->mode->height;
|
||||
struct v4l2_fwnode_device_properties props;
|
||||
- int exposure_max, exposure_def, hblank, pixel_rate;
|
||||
+ int exposure_max, exposure_def, hblank, pixel_rate, rate_factor;
|
||||
int i, ret;
|
||||
|
||||
ctrl_hdlr = &imx219->ctrl_handler;
|
||||
@@ -1353,8 +1406,12 @@ static int imx219_init_controls(struct i
|
||||
mutex_init(&imx219->mutex);
|
||||
ctrl_hdlr->lock = &imx219->mutex;
|
||||
|
||||
+ rate_factor = imx219_get_rate_factor(imx219);
|
||||
+ if (rate_factor < 0)
|
||||
+ return rate_factor;
|
||||
+
|
||||
/* By default, PIXEL_RATE is read only */
|
||||
- pixel_rate = IMX219_PIXEL_RATE * imx219->mode->rate_factor;
|
||||
+ pixel_rate = IMX219_PIXEL_RATE * rate_factor;
|
||||
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
|
||||
V4L2_CID_PIXEL_RATE,
|
||||
pixel_rate, pixel_rate,
|
||||
@@ -1576,6 +1633,9 @@ static int imx219_probe(struct i2c_clien
|
||||
goto error_power_off;
|
||||
usleep_range(100, 110);
|
||||
|
||||
+ /* Initialize default format */
|
||||
+ imx219_set_default_format(imx219);
|
||||
+
|
||||
ret = imx219_init_controls(imx219);
|
||||
if (ret)
|
||||
goto error_power_off;
|
||||
@@ -1590,9 +1650,6 @@ static int imx219_probe(struct i2c_clien
|
||||
imx219->pad[IMAGE_PAD].flags = MEDIA_PAD_FL_SOURCE;
|
||||
imx219->pad[METADATA_PAD].flags = MEDIA_PAD_FL_SOURCE;
|
||||
|
||||
- /* Initialize default format */
|
||||
- imx219_set_default_format(imx219);
|
||||
-
|
||||
ret = media_entity_pads_init(&imx219->sd.entity, NUM_PADS, imx219->pad);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init entity pads: %d\n", ret);
|
@ -0,0 +1,28 @@
|
||||
From 52039b6ffb6e78c2f77319b167dceab9aa51d13f Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 13 Jun 2023 16:12:54 +0100
|
||||
Subject: [PATCH] serial: sc16is7xx: Read modem line state at startup
|
||||
|
||||
This patch sets the driver modem line state to the actual line state
|
||||
at driver startup.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/5501
|
||||
|
||||
Signed-off-by: Earl Schmidt <schmidt.earl.f@gmail.com>
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/tty/serial/sc16is7xx.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/tty/serial/sc16is7xx.c
|
||||
+++ b/drivers/tty/serial/sc16is7xx.c
|
||||
@@ -1221,6 +1221,9 @@ static int sc16is7xx_startup(struct uart
|
||||
SC16IS7XX_IER_MSI_BIT;
|
||||
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
|
||||
|
||||
+ /* Initialize the Modem Control signals to current status */
|
||||
+ one->old_mctrl = sc16is7xx_get_hwmctrl(port);
|
||||
+
|
||||
/* Enable modem status polling */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
sc16is7xx_enable_ms(port);
|
@ -0,0 +1,79 @@
|
||||
From 6ef818eed60db70e9caf6bdf74cc1f9943994226 Mon Sep 17 00:00:00 2001
|
||||
From: Naushir Patuck <naush@raspberrypi.com>
|
||||
Date: Fri, 16 Jun 2023 16:24:19 +0100
|
||||
Subject: [PATCH] drivers: media: bcm2835_unicam: Improve frame sequence count
|
||||
handling
|
||||
|
||||
Ensure that the frame sequence counter is incremented only if a previous
|
||||
frame start interrupt has occurred, or a frame start + frame end has
|
||||
occurred simultaneously.
|
||||
|
||||
This corresponds the sequence number with the actual number of frames
|
||||
produced by the sensor, not the number of frame buffers dequeued back
|
||||
to userland.
|
||||
|
||||
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
---
|
||||
.../media/platform/bcm2835/bcm2835-unicam.c | 19 ++++++++++++++++++-
|
||||
1 file changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/media/platform/bcm2835/bcm2835-unicam.c
|
||||
+++ b/drivers/media/platform/bcm2835/bcm2835-unicam.c
|
||||
@@ -522,6 +522,7 @@ struct unicam_device {
|
||||
/* subdevice async Notifier */
|
||||
struct v4l2_async_notifier notifier;
|
||||
unsigned int sequence;
|
||||
+ bool frame_started;
|
||||
|
||||
/* ptr to sub device */
|
||||
struct v4l2_subdev *sensor;
|
||||
@@ -914,6 +915,8 @@ static irqreturn_t unicam_isr(int irq, v
|
||||
* buffer forever.
|
||||
*/
|
||||
if (fe) {
|
||||
+ bool inc_seq = unicam->frame_started;
|
||||
+
|
||||
/*
|
||||
* Ensure we have swapped buffers already as we can't
|
||||
* stop the peripheral. If no buffer is available, use a
|
||||
@@ -949,11 +952,23 @@ static irqreturn_t unicam_isr(int irq, v
|
||||
unicam_process_buffer_complete(node, sequence);
|
||||
node->cur_frm = node->next_frm;
|
||||
node->next_frm = NULL;
|
||||
+ inc_seq = true;
|
||||
} else {
|
||||
node->cur_frm = node->next_frm;
|
||||
}
|
||||
}
|
||||
- unicam->sequence++;
|
||||
+
|
||||
+ /*
|
||||
+ * Increment the sequence number conditionally on either a FS
|
||||
+ * having already occurred, or in the FE + FS condition as
|
||||
+ * caught in the FE handler above. This ensures the sequence
|
||||
+ * number corresponds to the frames generated by the sensor, not
|
||||
+ * the frames dequeued to userland.
|
||||
+ */
|
||||
+ if (inc_seq) {
|
||||
+ unicam->sequence++;
|
||||
+ unicam->frame_started = false;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (ista & UNICAM_FSI) {
|
||||
@@ -996,6 +1011,7 @@ static irqreturn_t unicam_isr(int irq, v
|
||||
}
|
||||
|
||||
unicam_queue_event_sof(unicam);
|
||||
+ unicam->frame_started = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2600,6 +2616,7 @@ static int unicam_start_streaming(struct
|
||||
vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
|
||||
}
|
||||
|
||||
+ dev->frame_started = false;
|
||||
unicam_start_rx(dev, buffer_addr);
|
||||
|
||||
ret = v4l2_subdev_call(dev->sensor, video, s_stream, 1);
|
@ -0,0 +1,41 @@
|
||||
From bd8e59b0456870997fb917bcd3b3b696e78d4ac2 Mon Sep 17 00:00:00 2001
|
||||
From: 6by9 <6by9@users.noreply.github.com>
|
||||
Date: Mon, 19 Jun 2023 16:02:36 +0100
|
||||
Subject: [PATCH] dtoverlays: Fix pitft[28|35] overlays for 6.1 driver change.
|
||||
(#5508)
|
||||
|
||||
The overlays configured both irq-gpio and an interrupts/
|
||||
interrupt-parent configuration for the stmpe MFD device.
|
||||
|
||||
irq-gpio was reworked in 6.1 and has issues with the configuration
|
||||
as provided. Removing it and using the interrupts/interrupt-parent
|
||||
configuration works fine, so do that.
|
||||
|
||||
See: https://forums.raspberrypi.com/viewtopic.php?t=351394
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts | 1 -
|
||||
arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts | 1 -
|
||||
2 files changed, 2 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/pitft28-resistive-overlay.dts
|
||||
@@ -68,7 +68,6 @@
|
||||
reg = <1>;
|
||||
|
||||
spi-max-frequency = <500000>;
|
||||
- irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */
|
||||
interrupts = <24 2>; /* high-to-low edge triggered */
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupt-controller;
|
||||
--- a/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/pitft35-resistive-overlay.dts
|
||||
@@ -68,7 +68,6 @@
|
||||
reg = <1>;
|
||||
|
||||
spi-max-frequency = <500000>;
|
||||
- irq-gpio = <&gpio 24 0x2>; /* IRQF_TRIGGER_FALLING */
|
||||
interrupts = <24 2>; /* high-to-low edge triggered */
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupt-controller;
|
@ -0,0 +1,23 @@
|
||||
From 713a7ef9d73fca0f7fed122cb854d930b7a6ba5a Mon Sep 17 00:00:00 2001
|
||||
From: Naushir Patuck <naush@raspberrypi.com>
|
||||
Date: Wed, 21 Jun 2023 08:45:02 +0100
|
||||
Subject: [PATCH] driver: media: i2c: imx477: Re-enable temperature sensor
|
||||
|
||||
The temperature sensor enable register write got lost at some point.
|
||||
Re-enable it.
|
||||
|
||||
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
---
|
||||
drivers/media/i2c/imx477.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/media/i2c/imx477.c
|
||||
+++ b/drivers/media/i2c/imx477.c
|
||||
@@ -167,6 +167,7 @@ struct imx477_mode {
|
||||
static const struct imx477_reg mode_common_regs[] = {
|
||||
{0x0136, 0x18},
|
||||
{0x0137, 0x00},
|
||||
+ {0x0138, 0x01},
|
||||
{0xe000, 0x00},
|
||||
{0xe07a, 0x01},
|
||||
{0x0808, 0x02},
|
@ -0,0 +1,25 @@
|
||||
From d4c3133378b377ee519ea50247339cd61221fc47 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 21 Jun 2023 09:20:36 +0100
|
||||
Subject: [PATCH] overlays: allo-katana-dac-audio: Reduce I2C clock
|
||||
|
||||
Higher speeds have been shown to cause data corruption on a Pi 4,
|
||||
possibly due to clock-stretching.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/5511
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/allo-katana-dac-audio-overlay.dts
|
||||
@@ -30,6 +30,7 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
+ clock-frequency = <50000>;
|
||||
|
||||
allo-katana-codec@30 {
|
||||
#sound-dai-cells = <0>;
|
@ -0,0 +1,308 @@
|
||||
From 76c457e7e2920342637b1955fbaadf2aae282f05 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 23 Jun 2023 09:48:59 +0100
|
||||
Subject: [PATCH] overlays: jedec-spi-nor: Add speed parameter
|
||||
|
||||
Add a speed parameter to the jedec-spi-nor overlay to allow much
|
||||
faster accesses, taking the opportunity to simplify the internals.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 8 +-
|
||||
.../dts/overlays/jedec-spi-nor-overlay.dts | 245 +++---------------
|
||||
2 files changed, 41 insertions(+), 212 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -2557,9 +2557,11 @@ Name: jedec-spi-nor
|
||||
Info: Adds support for JEDEC-compliant SPI NOR flash devices. (Note: The
|
||||
"jedec,spi-nor" kernel driver was formerly known as "m25p80".)
|
||||
Load: dtoverlay=jedec-spi-nor,<param>=<val>
|
||||
-Params: flash-spi<n>-<m> Enables flash device on SPI<n>, CS#<m>.
|
||||
- flash-fastr-spi<n>-<m> Enables flash device with fast read capability
|
||||
- on SPI<n>, CS#<m>.
|
||||
+Params: spi<n>-<m> Enable flash device on SPI<n>, CS#<m>
|
||||
+ fastr Add fast read capability to the flash device
|
||||
+ speed Maximum SPI frequency (Hz)
|
||||
+ flash-spi<n>-<m> Same as spi<n>-<m> (deprecated)
|
||||
+ flash-fastr-spi<n>-<m> Same as spi<n>->m>,fastr (deprecated)
|
||||
|
||||
|
||||
Name: justboom-both
|
||||
--- a/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/jedec-spi-nor-overlay.dts
|
||||
@@ -3,6 +3,7 @@
|
||||
// dtparams:
|
||||
// flash-spi<n>-<m> - Enables flash device on SPI<n>, CS#<m>.
|
||||
// flash-fastr-spi<n>-<m> - Enables flash device with fast read capability on SPI<n>, CS#<m>.
|
||||
+// speed - Set the SPI clock speed in Hz
|
||||
//
|
||||
// If devices are present on SPI1 or SPI2, those interfaces must be enabled with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
|
||||
//
|
||||
@@ -79,50 +80,23 @@
|
||||
};
|
||||
};
|
||||
|
||||
- // enable flash on spi0.0
|
||||
+ // Enable fast read for device
|
||||
+ // Use default active low interrupt signalling.
|
||||
fragment@8 {
|
||||
- target = <&spi0>;
|
||||
+ target = <&spi_nor>;
|
||||
__dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_00: spi_nor@0 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <0>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
+ m25p,fast-read;
|
||||
};
|
||||
};
|
||||
|
||||
- // enable flash on spi0.1
|
||||
- fragment@9 {
|
||||
+ payload: fragment@100 {
|
||||
target = <&spi0>;
|
||||
- __dormant__ {
|
||||
+ __overlay__ {
|
||||
status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_01: spi_nor@1 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <1>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
|
||||
- // enable flash on spi1.0
|
||||
- fragment@10 {
|
||||
- target = <&spi1>;
|
||||
- __dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_10: spi_nor@0 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
+ spi_nor: spi_nor@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <500000>;
|
||||
@@ -130,180 +104,33 @@
|
||||
};
|
||||
};
|
||||
|
||||
- // enable flash on spi1.1
|
||||
- fragment@11 {
|
||||
- target = <&spi1>;
|
||||
- __dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_11: spi_nor@1 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <1>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // enable flash on spi1.2
|
||||
- fragment@12 {
|
||||
- target = <&spi1>;
|
||||
- __dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_12: spi_nor@2 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <2>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // enable flash on spi2.0
|
||||
- fragment@13 {
|
||||
- target = <&spi2>;
|
||||
- __dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_20: spi_nor@0 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <0>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // enable flash on spi2.1
|
||||
- fragment@14 {
|
||||
- target = <&spi2>;
|
||||
- __dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_21: spi_nor@1 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <1>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // enable flash on spi2.2
|
||||
- fragment@15 {
|
||||
- target = <&spi2>;
|
||||
- __dormant__ {
|
||||
- status = "okay";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- spi_nor_22: spi_nor@2 {
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- compatible = "jedec,spi-nor";
|
||||
- reg = <2>;
|
||||
- spi-max-frequency = <500000>;
|
||||
- };
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi0.0.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@16 {
|
||||
- target = <&spi_nor_00>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi0.1.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@17 {
|
||||
- target = <&spi_nor_01>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi1.0.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@18 {
|
||||
- target = <&spi_nor_10>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi1.1.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@19 {
|
||||
- target = <&spi_nor_11>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi1.2.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@20 {
|
||||
- target = <&spi_nor_12>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi2.0.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@21 {
|
||||
- target = <&spi_nor_20>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi2.1.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@22 {
|
||||
- target = <&spi_nor_21>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
- // Enable fast read for device on spi2.2.
|
||||
- // Use default active low interrupt signalling.
|
||||
- fragment@23 {
|
||||
- target = <&spi_nor_22>;
|
||||
- __dormant__ {
|
||||
- m25p,fast-read;
|
||||
- };
|
||||
- };
|
||||
-
|
||||
__overrides__ {
|
||||
- flash-spi0-0 = <0>,"+0+8";
|
||||
- flash-spi0-1 = <0>,"+1+9";
|
||||
- flash-spi1-0 = <0>,"+2+10";
|
||||
- flash-spi1-1 = <0>,"+3+11";
|
||||
- flash-spi1-2 = <0>,"+4+12";
|
||||
- flash-spi2-0 = <0>,"+5+13";
|
||||
- flash-spi2-1 = <0>,"+6+14";
|
||||
- flash-spi2-2 = <0>,"+7+15";
|
||||
- flash-fastr-spi0-0 = <0>,"+0+8+16";
|
||||
- flash-fastr-spi0-1 = <0>,"+1+9+17";
|
||||
- flash-fastr-spi1-0 = <0>,"+2+10+18";
|
||||
- flash-fastr-spi1-1 = <0>,"+3+11+19";
|
||||
- flash-fastr-spi1-2 = <0>,"+4+12+20";
|
||||
- flash-fastr-spi2-0 = <0>,"+5+13+21";
|
||||
- flash-fastr-spi2-1 = <0>,"+6+14+22";
|
||||
- flash-fastr-spi2-2 = <0>,"+7+15+23";
|
||||
+ spi0-0 = <0>,"+0", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0";
|
||||
+ spi0-1 = <0>,"+1", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1";
|
||||
+ spi1-0 = <0>,"+2", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0";
|
||||
+ spi1-1 = <0>,"+3", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1";
|
||||
+ spi1-2 = <0>,"+4", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2";
|
||||
+ spi2-0 = <0>,"+5", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0";
|
||||
+ spi2-1 = <0>,"+6", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1";
|
||||
+ spi2-2 = <0>,"+7", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2";
|
||||
+ flash-spi0-0 = <0>,"+0", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0";
|
||||
+ flash-spi0-1 = <0>,"+1", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1";
|
||||
+ flash-spi1-0 = <0>,"+2", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0";
|
||||
+ flash-spi1-1 = <0>,"+3", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1";
|
||||
+ flash-spi1-2 = <0>,"+4", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2";
|
||||
+ flash-spi2-0 = <0>,"+5", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0";
|
||||
+ flash-spi2-1 = <0>,"+6", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1";
|
||||
+ flash-spi2-2 = <0>,"+7", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2";
|
||||
+ flash-fastr-spi0-0 = <0>,"+0+8", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=0";
|
||||
+ flash-fastr-spi0-1 = <0>,"+1+8", <&payload>,"target:0=",<&spi0>, <&spi_nor>,"reg:0=1";
|
||||
+ flash-fastr-spi1-0 = <0>,"+2+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=0";
|
||||
+ flash-fastr-spi1-1 = <0>,"+3+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=1";
|
||||
+ flash-fastr-spi1-2 = <0>,"+4+8", <&payload>,"target:0=",<&spi1>, <&spi_nor>,"reg:0=2";
|
||||
+ flash-fastr-spi2-0 = <0>,"+5+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=0";
|
||||
+ flash-fastr-spi2-1 = <0>,"+6+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=1";
|
||||
+ flash-fastr-spi2-2 = <0>,"+7+8", <&payload>,"target:0=",<&spi2>, <&spi_nor>,"reg:0=2";
|
||||
+ fastr = <0>,"+8";
|
||||
+ speed = <&spi_nor>, "spi-max-frequency:0";
|
||||
};
|
||||
};
|
||||
|
@ -0,0 +1,137 @@
|
||||
From e866f9fc7c6dd6af1e74ce6fa50db9ba21acae5e Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 24 Jun 2023 18:52:16 +0200
|
||||
Subject: [PATCH] ALSA: pcm: fix ELD constraints for (E)AC3, DTS(-HD) and MLP
|
||||
formats
|
||||
|
||||
commit 04b49b90caeed0b5544ff616d654900d27d403b6 upstream.
|
||||
|
||||
The SADs of compressed formats contain the channel and sample rate
|
||||
info of the audio data inside the compressed stream, but when
|
||||
building constraints we must use the rates and channels used to
|
||||
transport the compressed streams.
|
||||
|
||||
eg 48kHz 6ch EAC3 needs to be transmitted as a 2ch 192kHz stream.
|
||||
|
||||
This patch fixes the constraints for the common AC3 and DTS formats,
|
||||
the constraints for the less common MPEG, DSD etc formats are copied
|
||||
directly from the info in the SADs as before as I don't have the specs
|
||||
and equipment to test those.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
Link: https://lore.kernel.org/r/20230624165216.5719-1-hias@horus.com
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
sound/core/pcm_drm_eld.c | 73 ++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 70 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/sound/core/pcm_drm_eld.c
|
||||
+++ b/sound/core/pcm_drm_eld.c
|
||||
@@ -2,11 +2,25 @@
|
||||
/*
|
||||
* PCM DRM helpers
|
||||
*/
|
||||
+#include <linux/bitfield.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/hdmi.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
|
||||
+#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */
|
||||
+#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */
|
||||
+
|
||||
+#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */
|
||||
+#define SAD1_RATE_32000_MASK BIT(0)
|
||||
+#define SAD1_RATE_44100_MASK BIT(1)
|
||||
+#define SAD1_RATE_48000_MASK BIT(2)
|
||||
+#define SAD1_RATE_88200_MASK BIT(3)
|
||||
+#define SAD1_RATE_96000_MASK BIT(4)
|
||||
+#define SAD1_RATE_176400_MASK BIT(5)
|
||||
+#define SAD1_RATE_192000_MASK BIT(6)
|
||||
+
|
||||
static const unsigned int eld_rates[] = {
|
||||
32000,
|
||||
44100,
|
||||
@@ -17,9 +31,62 @@ static const unsigned int eld_rates[] =
|
||||
192000,
|
||||
};
|
||||
|
||||
+static unsigned int map_rate_families(const u8 *sad,
|
||||
+ unsigned int mask_32000,
|
||||
+ unsigned int mask_44100,
|
||||
+ unsigned int mask_48000)
|
||||
+{
|
||||
+ unsigned int rate_mask = 0;
|
||||
+
|
||||
+ if (sad[1] & SAD1_RATE_32000_MASK)
|
||||
+ rate_mask |= mask_32000;
|
||||
+ if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK))
|
||||
+ rate_mask |= mask_44100;
|
||||
+ if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK))
|
||||
+ rate_mask |= mask_48000;
|
||||
+ return rate_mask;
|
||||
+}
|
||||
+
|
||||
+static unsigned int sad_rate_mask(const u8 *sad)
|
||||
+{
|
||||
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_PCM:
|
||||
+ return sad[1] & SAD1_RATE_MASK;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ return map_rate_families(sad,
|
||||
+ SAD1_RATE_32000_MASK,
|
||||
+ SAD1_RATE_44100_MASK,
|
||||
+ SAD1_RATE_48000_MASK);
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return map_rate_families(sad,
|
||||
+ 0,
|
||||
+ SAD1_RATE_176400_MASK,
|
||||
+ SAD1_RATE_192000_MASK);
|
||||
+ default:
|
||||
+ /* TODO adjust for other compressed formats as well */
|
||||
+ return sad[1] & SAD1_RATE_MASK;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static unsigned int sad_max_channels(const u8 *sad)
|
||||
{
|
||||
- return 1 + (sad[0] & 7);
|
||||
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
|
||||
+ case HDMI_AUDIO_CODING_TYPE_PCM:
|
||||
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
|
||||
+ case HDMI_AUDIO_CODING_TYPE_AC3:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
|
||||
+ return 2;
|
||||
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
|
||||
+ case HDMI_AUDIO_CODING_TYPE_MLP:
|
||||
+ return 8;
|
||||
+ default:
|
||||
+ /* TODO adjust for other compressed formats as well */
|
||||
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
@@ -42,7 +109,7 @@ static int eld_limit_rates(struct snd_pc
|
||||
* requested number of channels.
|
||||
*/
|
||||
if (c->min <= max_channels)
|
||||
- rate_mask |= sad[1];
|
||||
+ rate_mask |= sad_rate_mask(sad);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +137,7 @@ static int eld_limit_channels(struct snd
|
||||
rate_mask |= BIT(i);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
|
||||
- if (rate_mask & sad[1])
|
||||
+ if (rate_mask & sad_rate_mask(sad))
|
||||
t.max = max(t.max, sad_max_channels(sad));
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
From 3f388718331b5ce2acd34730448db001759868aa Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 24 Jun 2023 18:52:32 +0200
|
||||
Subject: [PATCH] ASoC: hdmi-codec: fix channel info for compressed formats
|
||||
|
||||
commit 4e0871333661d2ec0ed3dc00a945c2160eccae77 upstream.
|
||||
|
||||
According to CTA 861 the channel/speaker allocation info in the
|
||||
audio infoframe only applies to uncompressed (PCM) audio streams.
|
||||
|
||||
The channel count info should indicate the number of channels
|
||||
in the transmitted audio, which usually won't match the number of
|
||||
channels used to transmit the compressed bitstream.
|
||||
|
||||
Some devices (eg some Sony TVs) will refuse to decode compressed
|
||||
audio if these values are not set correctly.
|
||||
|
||||
To fix this we can simply set the channel count to 0 (which means
|
||||
"refer to stream header") and set the channel/speaker allocation to 0
|
||||
as well (which would mean stereo FL/FR for PCM, a safe value all sinks
|
||||
will support) when transmitting compressed audio.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
Link: https://lore.kernel.org/r/20230624165232.5751-1-hias@horus.com
|
||||
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
||||
---
|
||||
sound/soc/codecs/hdmi-codec.c | 36 +++++++++++++++++++++++------------
|
||||
1 file changed, 24 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/sound/soc/codecs/hdmi-codec.c
|
||||
+++ b/sound/soc/codecs/hdmi-codec.c
|
||||
@@ -484,31 +484,43 @@ static int hdmi_codec_fill_codec_params(
|
||||
struct hdmi_codec_params *hp)
|
||||
{
|
||||
struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
|
||||
- int idx;
|
||||
+ int idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
+ u8 ca_id = 0;
|
||||
+ bool pcm_audio = !(hcp->iec_status[0] & IEC958_AES0_NONAUDIO);
|
||||
+
|
||||
+ if (pcm_audio) {
|
||||
+ /* Select a channel allocation that matches with ELD and pcm channels */
|
||||
+ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
|
||||
+
|
||||
+ if (idx < 0) {
|
||||
+ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
+ idx);
|
||||
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
+ return idx;
|
||||
+ }
|
||||
|
||||
- /* Select a channel allocation that matches with ELD and pcm channels */
|
||||
- idx = hdmi_codec_get_ch_alloc_table_idx(hcp, channels);
|
||||
- if (idx < 0) {
|
||||
- dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
|
||||
- idx);
|
||||
- hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
|
||||
- return idx;
|
||||
+ ca_id = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
}
|
||||
|
||||
memset(hp, 0, sizeof(*hp));
|
||||
|
||||
hdmi_audio_infoframe_init(&hp->cea);
|
||||
- hp->cea.channels = channels;
|
||||
+
|
||||
+ if (pcm_audio)
|
||||
+ hp->cea.channels = channels;
|
||||
+ else
|
||||
+ hp->cea.channels = 0;
|
||||
+
|
||||
hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
|
||||
hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
|
||||
hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
|
||||
- hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
+ hp->cea.channel_allocation = ca_id;
|
||||
|
||||
hp->sample_width = sample_width;
|
||||
hp->sample_rate = sample_rate;
|
||||
hp->channels = channels;
|
||||
|
||||
- hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
|
||||
+ hcp->chmap_idx = idx;
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
From 9c5a7f04cab6b020389d7c5af155b1ee7f46537d Mon Sep 17 00:00:00 2001
|
||||
From: Lee Jackson <lee.jackson@arducam.com>
|
||||
Date: Thu, 4 May 2023 11:14:04 +0800
|
||||
Subject: [PATCH] media: i2c: arducam_64mp: Modify the line length of 1280x720
|
||||
resolution
|
||||
|
||||
Arducam 64MP has specific requirements for the line length, and if these
|
||||
conditions are not met, the camera will not function properly. Under the
|
||||
previous configuration, once a stream off operation is performed, the
|
||||
camera will not output any data, even if a stream on operation is
|
||||
performed. This prevents us from switching from 1280x720 to another
|
||||
resolution.
|
||||
|
||||
Signed-off-by: Lee Jackson <lee.jackson@arducam.com>
|
||||
---
|
||||
drivers/media/i2c/arducam_64mp.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/media/i2c/arducam_64mp.c
|
||||
+++ b/drivers/media/i2c/arducam_64mp.c
|
||||
@@ -1063,10 +1063,10 @@ static const struct arducam_64mp_reg mod
|
||||
|
||||
/* 720p 120fps mode */
|
||||
static const struct arducam_64mp_reg mode_1280x720_regs[] = {
|
||||
- {0x0342, 0x1d},
|
||||
- {0x0343, 0xc4},
|
||||
- {0x0340, 0x03},
|
||||
- {0x0341, 0xd8},
|
||||
+ {0x0342, 0x1b},
|
||||
+ {0x0343, 0x08},
|
||||
+ {0x0340, 0x04},
|
||||
+ {0x0341, 0x3b},
|
||||
{0x0344, 0x08},
|
||||
{0x0345, 0x10},
|
||||
{0x0346, 0x07},
|
||||
@@ -1209,7 +1209,7 @@ static const struct arducam_64mp_mode su
|
||||
}, {
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
- .line_length_pix = 0x1dc4,
|
||||
+ .line_length_pix = 0x1b08,
|
||||
.crop = {
|
||||
.left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 2064,
|
||||
.top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 2032,
|
@ -0,0 +1,105 @@
|
||||
From 7b3d0124c5cf462d5be0b0d4e558002b74750911 Mon Sep 17 00:00:00 2001
|
||||
From: Lee Jackson <lee.jackson@arducam.com>
|
||||
Date: Fri, 5 May 2023 14:36:15 +0800
|
||||
Subject: [PATCH] media: i2c: arducam_64mp: Add 8000x6000 resolution
|
||||
|
||||
Added 8000x6000 10-bit (cropped) @ 3fps mode for Arducam 64MP
|
||||
|
||||
Signed-off-by: Lee Jackson <lee.jackson@arducam.com>
|
||||
---
|
||||
drivers/media/i2c/arducam_64mp.c | 77 ++++++++++++++++++++++++++++++++
|
||||
1 file changed, 77 insertions(+)
|
||||
|
||||
--- a/drivers/media/i2c/arducam_64mp.c
|
||||
+++ b/drivers/media/i2c/arducam_64mp.c
|
||||
@@ -849,6 +849,65 @@ static const struct arducam_64mp_reg mod
|
||||
{0x020f, 0x00},
|
||||
};
|
||||
|
||||
+/* 48 mpix 3.0fps */
|
||||
+static const struct arducam_64mp_reg mode_8000x6000_regs[] = {
|
||||
+ {0x0342, 0xb6},
|
||||
+ {0x0343, 0xb2},
|
||||
+ {0x0340, 0x19},
|
||||
+ {0x0341, 0x0e},
|
||||
+ {0x0344, 0x02},
|
||||
+ {0x0345, 0x70},
|
||||
+ {0x0346, 0x01},
|
||||
+ {0x0347, 0xd8},
|
||||
+ {0x0348, 0x21},
|
||||
+ {0x0349, 0xaf},
|
||||
+ {0x034a, 0x19},
|
||||
+ {0x034b, 0x47},
|
||||
+ {0x0900, 0x00},
|
||||
+ {0x0901, 0x11},
|
||||
+ {0x0902, 0x0a},
|
||||
+ {0x30d8, 0x00},
|
||||
+ {0x3200, 0x01},
|
||||
+ {0x3201, 0x01},
|
||||
+ {0x0408, 0x00},
|
||||
+ {0x0409, 0x00},
|
||||
+ {0x040a, 0x00},
|
||||
+ {0x040b, 0x00},
|
||||
+ {0x040c, 0x1f},
|
||||
+ {0x040d, 0x40},
|
||||
+ {0x040e, 0x17},
|
||||
+ {0x040f, 0x70},
|
||||
+ {0x034c, 0x1f},
|
||||
+ {0x034d, 0x40},
|
||||
+ {0x034e, 0x17},
|
||||
+ {0x034f, 0x70},
|
||||
+ {0x30d9, 0x01},
|
||||
+ {0x32d5, 0x01},
|
||||
+ {0x32d6, 0x00},
|
||||
+ {0x401e, 0x00},
|
||||
+ {0x40b8, 0x04},
|
||||
+ {0x40b9, 0x20},
|
||||
+ {0x40bc, 0x02},
|
||||
+ {0x40bd, 0x58},
|
||||
+ {0x40be, 0x02},
|
||||
+ {0x40bf, 0x58},
|
||||
+ {0x41a4, 0x00},
|
||||
+ {0x5a09, 0x01},
|
||||
+ {0x5a17, 0x01},
|
||||
+ {0x5a25, 0x01},
|
||||
+ {0x5a33, 0x01},
|
||||
+ {0x98d7, 0x14},
|
||||
+ {0x98d8, 0x14},
|
||||
+ {0x98d9, 0x00},
|
||||
+ {0x99c4, 0x00},
|
||||
+ {0x0202, 0x03},
|
||||
+ {0x0203, 0xe8},
|
||||
+ {0x0204, 0x00},
|
||||
+ {0x0205, 0x00},
|
||||
+ {0x020e, 0x01},
|
||||
+ {0x020f, 0x00},
|
||||
+};
|
||||
+
|
||||
/* 16 mpix 10fps */
|
||||
static const struct arducam_64mp_reg mode_4624x3472_regs[] = {
|
||||
{0x0342, 0x63},
|
||||
@@ -1135,6 +1194,24 @@ static const struct arducam_64mp_mode su
|
||||
.regs = mode_9152x6944_regs,
|
||||
}
|
||||
}, {
|
||||
+ .width = 8000,
|
||||
+ .height = 6000,
|
||||
+ .line_length_pix = 0xb6b2,
|
||||
+ .crop = {
|
||||
+ .left = ARDUCAM_64MP_PIXEL_ARRAY_LEFT + 624,
|
||||
+ .top = ARDUCAM_64MP_PIXEL_ARRAY_TOP + 472,
|
||||
+ .width = 9248,
|
||||
+ .height = 6944,
|
||||
+ },
|
||||
+ .timeperframe_default = {
|
||||
+ .numerator = 100,
|
||||
+ .denominator = 300
|
||||
+ },
|
||||
+ .reg_list = {
|
||||
+ .num_of_regs = ARRAY_SIZE(mode_8000x6000_regs),
|
||||
+ .regs = mode_8000x6000_regs,
|
||||
+ }
|
||||
+ }, {
|
||||
.width = 4624,
|
||||
.height = 3472,
|
||||
.line_length_pix = 0x6397,
|
@ -0,0 +1,163 @@
|
||||
From b9d2d1862aa5b798cecb87a95d970ad34a4aebc0 Mon Sep 17 00:00:00 2001
|
||||
From: Lee Jackson <lee.jackson@arducam.com>
|
||||
Date: Tue, 30 May 2023 15:50:05 +0800
|
||||
Subject: [PATCH] media: i2c: arducam_64mp: Add PDAF support
|
||||
|
||||
Enable PDAF output for all modes, and also need to modify Embedded Line
|
||||
Width to 11560 * 3 (two lines of Embedded Data + one line of PDAF).
|
||||
|
||||
Signed-off-by: Lee Jackson <lee.jackson@arducam.com>
|
||||
---
|
||||
drivers/media/i2c/arducam_64mp.c | 64 ++++++++++++++++++++++++++++++--
|
||||
1 file changed, 61 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/media/i2c/arducam_64mp.c
|
||||
+++ b/drivers/media/i2c/arducam_64mp.c
|
||||
@@ -95,7 +95,7 @@
|
||||
#define ARDUCAM_64MP_TEST_PATTERN_GB_DEFAULT 0
|
||||
|
||||
/* Embedded metadata stream structure */
|
||||
-#define ARDUCAM_64MP_EMBEDDED_LINE_WIDTH 16384
|
||||
+#define ARDUCAM_64MP_EMBEDDED_LINE_WIDTH (11560 * 3)
|
||||
#define ARDUCAM_64MP_NUM_EMBEDDED_LINES 1
|
||||
|
||||
enum pad_types {
|
||||
@@ -144,6 +144,7 @@ struct arducam_64mp_mode {
|
||||
};
|
||||
|
||||
static const struct arducam_64mp_reg mode_common_regs[] = {
|
||||
+ {0x0100, 0x00},
|
||||
{0x0136, 0x18},
|
||||
{0x0137, 0x00},
|
||||
{0x33F0, 0x01},
|
||||
@@ -788,6 +789,7 @@ static const struct arducam_64mp_reg mod
|
||||
{0x3092, 0x01},
|
||||
{0x3093, 0x00},
|
||||
{0x0350, 0x00},
|
||||
+ {0x3419, 0x00},
|
||||
};
|
||||
|
||||
/* 64 mpix 2.7fps */
|
||||
@@ -847,6 +849,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x0205, 0x00},
|
||||
{0x020e, 0x01},
|
||||
{0x020f, 0x00},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x02},
|
||||
+ {0x341f, 0x3c},
|
||||
+ {0x3420, 0x02},
|
||||
+ {0x3421, 0x42},
|
||||
};
|
||||
|
||||
/* 48 mpix 3.0fps */
|
||||
@@ -906,6 +916,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x0205, 0x00},
|
||||
{0x020e, 0x01},
|
||||
{0x020f, 0x00},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x01},
|
||||
+ {0x341f, 0xf4},
|
||||
+ {0x3420, 0x01},
|
||||
+ {0x3421, 0xf4},
|
||||
};
|
||||
|
||||
/* 16 mpix 10fps */
|
||||
@@ -959,6 +977,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x98d8, 0x8c},
|
||||
{0x98d9, 0x0a},
|
||||
{0x99c4, 0x16},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x01},
|
||||
+ {0x341f, 0x21},
|
||||
+ {0x3420, 0x01},
|
||||
+ {0x3421, 0x21},
|
||||
};
|
||||
|
||||
/* 4k 20fps mode */
|
||||
@@ -1012,6 +1038,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x98d8, 0x8c},
|
||||
{0x98d9, 0x0a},
|
||||
{0x99c4, 0x16},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x00},
|
||||
+ {0x341f, 0xf0},
|
||||
+ {0x3420, 0x00},
|
||||
+ {0x3421, 0xb4},
|
||||
};
|
||||
|
||||
/* 4x4 binned 30fps mode */
|
||||
@@ -1031,7 +1065,7 @@ static const struct arducam_64mp_reg mod
|
||||
{0x0900, 0x01},
|
||||
{0x0901, 0x44},
|
||||
{0x0902, 0x08},
|
||||
- {0x30d8, 0x00},
|
||||
+ {0x30d8, 0x04},
|
||||
{0x3200, 0x43},
|
||||
{0x3201, 0x43},
|
||||
{0x0408, 0x00},
|
||||
@@ -1046,7 +1080,7 @@ static const struct arducam_64mp_reg mod
|
||||
{0x034d, 0x08},
|
||||
{0x034e, 0x06},
|
||||
{0x034f, 0xc8},
|
||||
- {0x30d9, 0x01},
|
||||
+ {0x30d9, 0x00},
|
||||
{0x32d5, 0x00},
|
||||
{0x32d6, 0x00},
|
||||
{0x401e, 0x00},
|
||||
@@ -1065,6 +1099,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x98d8, 0x8c},
|
||||
{0x98d9, 0x0a},
|
||||
{0x99c4, 0x16},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x00},
|
||||
+ {0x341f, 0x90},
|
||||
+ {0x3420, 0x00},
|
||||
+ {0x3421, 0x90},
|
||||
};
|
||||
|
||||
/* 1080p 60fps mode */
|
||||
@@ -1118,6 +1160,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x98d8, 0x8c},
|
||||
{0x98d9, 0x0a},
|
||||
{0x99c4, 0x16},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x00},
|
||||
+ {0x341f, 0x78},
|
||||
+ {0x3420, 0x00},
|
||||
+ {0x3421, 0x5a},
|
||||
};
|
||||
|
||||
/* 720p 120fps mode */
|
||||
@@ -1171,6 +1221,14 @@ static const struct arducam_64mp_reg mod
|
||||
{0x98d8, 0x8c},
|
||||
{0x98d9, 0x0a},
|
||||
{0x99c4, 0x16},
|
||||
+ {0x341a, 0x00},
|
||||
+ {0x341b, 0x00},
|
||||
+ {0x341c, 0x00},
|
||||
+ {0x341d, 0x00},
|
||||
+ {0x341e, 0x00},
|
||||
+ {0x341f, 0x50},
|
||||
+ {0x3420, 0x00},
|
||||
+ {0x3421, 0x3c},
|
||||
};
|
||||
|
||||
/* Mode configs */
|
@ -0,0 +1,24 @@
|
||||
From 6f4106f7a7fdcbc03290008713915b4122988c90 Mon Sep 17 00:00:00 2001
|
||||
From: James Hughes <JamesH65@users.noreply.github.com>
|
||||
Date: Wed, 5 Jul 2023 15:43:30 +0100
|
||||
Subject: [PATCH] overlays: audremap: Document CM4 40&41 restriction
|
||||
|
||||
Update audremap information to state pins 40,41 are not available on the CM4.
|
||||
|
||||
Signed-off-by: James Hughes (james.hughes@raspberrypi.com)
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -703,7 +703,8 @@ Params: swap_lr Reverse
|
||||
nothing on BCM2711 (default off)
|
||||
pins_12_13 Select GPIOs 12 & 13 (default)
|
||||
pins_18_19 Select GPIOs 18 & 19
|
||||
- pins_40_41 Select GPIOs 40 & 41
|
||||
+ pins_40_41 Select GPIOs 40 & 41 (not available on CM4, used
|
||||
+ for other purposes)
|
||||
pins_40_45 Select GPIOs 40 & 45 (don't use on BCM2711 - the
|
||||
pins are on different controllers)
|
||||
|
@ -0,0 +1,120 @@
|
||||
From 1d15e6a34222cc8d8eb1050e7a3e276b0348be41 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 3 Jul 2023 11:04:56 +0100
|
||||
Subject: [PATCH] fixup! Allow mac address to be set in smsc95xx
|
||||
|
||||
usbnet: smsc95xx: Fix indentation of smsc95xx_is_macaddr_param()
|
||||
|
||||
smsc95xx_is_macaddr_param() is incorrectly indented, it uses 7 spaces
|
||||
instead of tabs. Fix it.
|
||||
|
||||
Fixes: aac7b105788e ("Allow mac address to be set in smsc95xx")
|
||||
Signed-off-by: Philipp Rosenberger <p.rosenberger@kunbus.com>
|
||||
[lukas: fix netif_dbg() indentation as well, wordsmith commit message]
|
||||
Signed-off-by: Lukas Wunner <lukas@wunner.de>
|
||||
|
||||
usbnet: smsc95xx: Simplify MAC address parsing
|
||||
|
||||
Parsing the MAC address provided on the kernel command line can be
|
||||
simplified quite a bit by taking advantage of the kernel's built-in
|
||||
mac_pton() helper.
|
||||
|
||||
Likewise emitting the MAC address can be simplified with the %pM
|
||||
format string conversion.
|
||||
|
||||
Signed-off-by: Lukas Wunner <lukas@wunner.de>
|
||||
|
||||
usbnet: smsc95xx: Fix style issues in smsc95xx_is_macaddr_param()
|
||||
|
||||
It is bad practice to have a function named ..._is_...() which has side
|
||||
effects. So drop the 'is' from the name.
|
||||
|
||||
Per kernel convention return 0 on success and a negative errno on
|
||||
failure.
|
||||
|
||||
Validate the MAC address retrieved from the command line.
|
||||
|
||||
Signed-off-by: Philipp Rosenberger <p.rosenberger@kunbus.com>
|
||||
[lukas: leave 2nd function parameter unchanged, wordsmith commit message]
|
||||
Signed-off-by: Lukas Wunner <lukas@wunner.de>
|
||||
---
|
||||
drivers/net/usb/smsc95xx.c | 61 +++++++++++---------------------------
|
||||
1 file changed, 17 insertions(+), 44 deletions(-)
|
||||
|
||||
--- a/drivers/net/usb/smsc95xx.c
|
||||
+++ b/drivers/net/usb/smsc95xx.c
|
||||
@@ -814,49 +814,18 @@ static int smsc95xx_ioctl(struct net_dev
|
||||
}
|
||||
|
||||
/* Check the macaddr module parameter for a MAC address */
|
||||
-static int smsc95xx_is_macaddr_param(struct usbnet *dev, struct net_device *nd)
|
||||
+static int smsc95xx_macaddr_param(struct usbnet *dev, struct net_device *nd)
|
||||
{
|
||||
- int i, j, got_num, num;
|
||||
- u8 mtbl[ETH_ALEN];
|
||||
+ u8 mtbl[ETH_ALEN];
|
||||
|
||||
- if (macaddr[0] == ':')
|
||||
- return 0;
|
||||
-
|
||||
- i = 0;
|
||||
- j = 0;
|
||||
- num = 0;
|
||||
- got_num = 0;
|
||||
- while (j < ETH_ALEN) {
|
||||
- if (macaddr[i] && macaddr[i] != ':') {
|
||||
- got_num++;
|
||||
- if ('0' <= macaddr[i] && macaddr[i] <= '9')
|
||||
- num = num * 16 + macaddr[i] - '0';
|
||||
- else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
|
||||
- num = num * 16 + 10 + macaddr[i] - 'A';
|
||||
- else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
|
||||
- num = num * 16 + 10 + macaddr[i] - 'a';
|
||||
- else
|
||||
- break;
|
||||
- i++;
|
||||
- } else if (got_num == 2) {
|
||||
- mtbl[j++] = (u8) num;
|
||||
- num = 0;
|
||||
- got_num = 0;
|
||||
- i++;
|
||||
- } else {
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (j == ETH_ALEN) {
|
||||
- netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
|
||||
- "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
|
||||
- mtbl[3], mtbl[4], mtbl[5]);
|
||||
- dev_addr_mod(nd, 0, mtbl, ETH_ALEN);
|
||||
- return 1;
|
||||
- } else {
|
||||
- return 0;
|
||||
- }
|
||||
+ 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)
|
||||
@@ -883,8 +852,12 @@ static void smsc95xx_init_mac_address(st
|
||||
}
|
||||
|
||||
/* Check module parameters */
|
||||
- if (smsc95xx_is_macaddr_param(dev, dev->net))
|
||||
- return;
|
||||
+ 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);
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,329 @@
|
||||
From 3ece03b1575b0c3a0989e372aaaa4557ae74dc89 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Thu, 20 Jul 2023 11:28:20 +0100
|
||||
Subject: [PATCH] fixup! Add support for all the downstream rpi sound card
|
||||
drivers
|
||||
|
||||
Replace the Allo Dac clock driver with an extension of the
|
||||
HiFiBerry clock driver that it cloned.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/clk/Makefile | 1 -
|
||||
drivers/clk/clk-allo-dac.c | 161 -----------------------------
|
||||
drivers/clk/clk-hifiberry-dacpro.c | 57 ++++++----
|
||||
sound/soc/bcm/Kconfig | 1 +
|
||||
4 files changed, 40 insertions(+), 180 deletions(-)
|
||||
delete mode 100644 drivers/clk/clk-allo-dac.c
|
||||
|
||||
--- a/drivers/clk/Makefile
|
||||
+++ b/drivers/clk/Makefile
|
||||
@@ -19,7 +19,6 @@ endif
|
||||
|
||||
# hardware specific clock types
|
||||
# please keep this section sorted lexicographically by file path name
|
||||
-obj-$(CONFIG_SND_BCM2708_SOC_ALLO_BOSS_DAC) += clk-allo-dac.o
|
||||
obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o
|
||||
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
|
||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
|
||||
--- a/drivers/clk/clk-allo-dac.c
|
||||
+++ /dev/null
|
||||
@@ -1,161 +0,0 @@
|
||||
-/*
|
||||
- * Clock Driver for Allo DAC
|
||||
- *
|
||||
- * Author: Baswaraj K <jaikumar@cem-solutions.net>
|
||||
- * Copyright 2016
|
||||
- * based on code by Stuart MacLean
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or
|
||||
- * modify it under the terms of the GNU General Public License
|
||||
- * version 2 as published by the Free Software Foundation.
|
||||
- *
|
||||
- * This program is distributed in the hope that it will be useful, but
|
||||
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
- * General Public License for more details.
|
||||
- */
|
||||
-
|
||||
-#include <linux/clk-provider.h>
|
||||
-#include <linux/clkdev.h>
|
||||
-#include <linux/kernel.h>
|
||||
-#include <linux/module.h>
|
||||
-#include <linux/of.h>
|
||||
-#include <linux/slab.h>
|
||||
-#include <linux/platform_device.h>
|
||||
-
|
||||
-/* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
-#define CLK_44EN_RATE 45158400UL
|
||||
-/* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
-#define CLK_48EN_RATE 49152000UL
|
||||
-
|
||||
-/**
|
||||
- * struct allo_dac_clk - Common struct to the Allo DAC
|
||||
- * @hw: clk_hw for the common clk framework
|
||||
- * @mode: 0 => CLK44EN, 1 => CLK48EN
|
||||
- */
|
||||
-struct clk_allo_hw {
|
||||
- struct clk_hw hw;
|
||||
- uint8_t mode;
|
||||
-};
|
||||
-
|
||||
-#define to_allo_clk(_hw) container_of(_hw, struct clk_allo_hw, hw)
|
||||
-
|
||||
-static const struct of_device_id clk_allo_dac_dt_ids[] = {
|
||||
- { .compatible = "allo,dac-clk",},
|
||||
- { }
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(of, clk_allo_dac_dt_ids);
|
||||
-
|
||||
-static unsigned long clk_allo_dac_recalc_rate(struct clk_hw *hw,
|
||||
- unsigned long parent_rate)
|
||||
-{
|
||||
- return (to_allo_clk(hw)->mode == 0) ? CLK_44EN_RATE :
|
||||
- CLK_48EN_RATE;
|
||||
-}
|
||||
-
|
||||
-static long clk_allo_dac_round_rate(struct clk_hw *hw,
|
||||
- unsigned long rate, unsigned long *parent_rate)
|
||||
-{
|
||||
- long actual_rate;
|
||||
-
|
||||
- if (rate <= CLK_44EN_RATE) {
|
||||
- actual_rate = (long)CLK_44EN_RATE;
|
||||
- } else if (rate >= CLK_48EN_RATE) {
|
||||
- actual_rate = (long)CLK_48EN_RATE;
|
||||
- } else {
|
||||
- long diff44Rate = (long)(rate - CLK_44EN_RATE);
|
||||
- long diff48Rate = (long)(CLK_48EN_RATE - rate);
|
||||
-
|
||||
- if (diff44Rate < diff48Rate)
|
||||
- actual_rate = (long)CLK_44EN_RATE;
|
||||
- else
|
||||
- actual_rate = (long)CLK_48EN_RATE;
|
||||
- }
|
||||
- return actual_rate;
|
||||
-}
|
||||
-
|
||||
-
|
||||
-static int clk_allo_dac_set_rate(struct clk_hw *hw,
|
||||
- unsigned long rate, unsigned long parent_rate)
|
||||
-{
|
||||
- unsigned long actual_rate;
|
||||
- struct clk_allo_hw *clk = to_allo_clk(hw);
|
||||
-
|
||||
- actual_rate = (unsigned long)clk_allo_dac_round_rate(hw, rate,
|
||||
- &parent_rate);
|
||||
- clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-
|
||||
-const struct clk_ops clk_allo_dac_rate_ops = {
|
||||
- .recalc_rate = clk_allo_dac_recalc_rate,
|
||||
- .round_rate = clk_allo_dac_round_rate,
|
||||
- .set_rate = clk_allo_dac_set_rate,
|
||||
-};
|
||||
-
|
||||
-static int clk_allo_dac_probe(struct platform_device *pdev)
|
||||
-{
|
||||
- int ret;
|
||||
- struct clk_allo_hw *proclk;
|
||||
- struct clk *clk;
|
||||
- struct device *dev;
|
||||
- struct clk_init_data init;
|
||||
-
|
||||
- dev = &pdev->dev;
|
||||
-
|
||||
- proclk = kzalloc(sizeof(struct clk_allo_hw), GFP_KERNEL);
|
||||
- if (!proclk)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- init.name = "clk-allo-dac";
|
||||
- init.ops = &clk_allo_dac_rate_ops;
|
||||
- init.flags = 0;
|
||||
- init.parent_names = NULL;
|
||||
- init.num_parents = 0;
|
||||
-
|
||||
- proclk->mode = 0;
|
||||
- proclk->hw.init = &init;
|
||||
-
|
||||
- clk = devm_clk_register(dev, &proclk->hw);
|
||||
- if (!IS_ERR(clk)) {
|
||||
- ret = of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
|
||||
- clk);
|
||||
- } else {
|
||||
- dev_err(dev, "Fail to register clock driver\n");
|
||||
- kfree(proclk);
|
||||
- ret = PTR_ERR(clk);
|
||||
- }
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static int clk_allo_dac_remove(struct platform_device *pdev)
|
||||
-{
|
||||
- of_clk_del_provider(pdev->dev.of_node);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static struct platform_driver clk_allo_dac_driver = {
|
||||
- .probe = clk_allo_dac_probe,
|
||||
- .remove = clk_allo_dac_remove,
|
||||
- .driver = {
|
||||
- .name = "clk-allo-dac",
|
||||
- .of_match_table = clk_allo_dac_dt_ids,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-static int __init clk_allo_dac_init(void)
|
||||
-{
|
||||
- return platform_driver_register(&clk_allo_dac_driver);
|
||||
-}
|
||||
-core_initcall(clk_allo_dac_init);
|
||||
-
|
||||
-static void __exit clk_allo_dac_exit(void)
|
||||
-{
|
||||
- platform_driver_unregister(&clk_allo_dac_driver);
|
||||
-}
|
||||
-module_exit(clk_allo_dac_exit);
|
||||
-
|
||||
-MODULE_DESCRIPTION("Allo DAC clock driver");
|
||||
-MODULE_LICENSE("GPL v2");
|
||||
-MODULE_ALIAS("platform:clk-allo-dac");
|
||||
--- a/drivers/clk/clk-hifiberry-dacpro.c
|
||||
+++ b/drivers/clk/clk-hifiberry-dacpro.c
|
||||
@@ -22,10 +22,12 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
-/* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
-#define CLK_44EN_RATE 22579200UL
|
||||
-/* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
-#define CLK_48EN_RATE 24576000UL
|
||||
+struct ext_clk_rates {
|
||||
+ /* Clock rate of CLK44EN attached to GPIO6 pin */
|
||||
+ unsigned long clk_44en;
|
||||
+ /* Clock rate of CLK48EN attached to GPIO3 pin */
|
||||
+ unsigned long clk_48en;
|
||||
+};
|
||||
|
||||
/**
|
||||
* struct hifiberry_dacpro_clk - Common struct to the HiFiBerry DAC Pro
|
||||
@@ -35,12 +37,24 @@
|
||||
struct clk_hifiberry_hw {
|
||||
struct clk_hw hw;
|
||||
uint8_t mode;
|
||||
+ struct ext_clk_rates clk_rates;
|
||||
};
|
||||
|
||||
#define to_hifiberry_clk(_hw) container_of(_hw, struct clk_hifiberry_hw, hw)
|
||||
|
||||
+static const struct ext_clk_rates hifiberry_dacpro_clks = {
|
||||
+ .clk_44en = 22579200UL,
|
||||
+ .clk_48en = 24576000UL,
|
||||
+};
|
||||
+
|
||||
+static const struct ext_clk_rates allo_dac_clks = {
|
||||
+ .clk_44en = 45158400UL,
|
||||
+ .clk_48en = 49152000UL,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id clk_hifiberry_dacpro_dt_ids[] = {
|
||||
- { .compatible = "hifiberry,dacpro-clk",},
|
||||
+ { .compatible = "hifiberry,dacpro-clk", &hifiberry_dacpro_clks },
|
||||
+ { .compatible = "allo,dac-clk", &allo_dac_clks },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_hifiberry_dacpro_dt_ids);
|
||||
@@ -48,27 +62,29 @@ MODULE_DEVICE_TABLE(of, clk_hifiberry_da
|
||||
static unsigned long clk_hifiberry_dacpro_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
- return (to_hifiberry_clk(hw)->mode == 0) ? CLK_44EN_RATE :
|
||||
- CLK_48EN_RATE;
|
||||
+ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
|
||||
+ return (clk->mode == 0) ? clk->clk_rates.clk_44en :
|
||||
+ clk->clk_rates.clk_48en;
|
||||
}
|
||||
|
||||
static long clk_hifiberry_dacpro_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *parent_rate)
|
||||
{
|
||||
+ struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
|
||||
long actual_rate;
|
||||
|
||||
- if (rate <= CLK_44EN_RATE) {
|
||||
- actual_rate = (long)CLK_44EN_RATE;
|
||||
- } else if (rate >= CLK_48EN_RATE) {
|
||||
- actual_rate = (long)CLK_48EN_RATE;
|
||||
+ if (rate <= clk->clk_rates.clk_44en) {
|
||||
+ actual_rate = (long)clk->clk_rates.clk_44en;
|
||||
+ } else if (rate >= clk->clk_rates.clk_48en) {
|
||||
+ actual_rate = (long)clk->clk_rates.clk_48en;
|
||||
} else {
|
||||
- long diff44Rate = (long)(rate - CLK_44EN_RATE);
|
||||
- long diff48Rate = (long)(CLK_48EN_RATE - rate);
|
||||
+ long diff44Rate = (long)(rate - clk->clk_rates.clk_44en);
|
||||
+ long diff48Rate = (long)(clk->clk_rates.clk_48en - rate);
|
||||
|
||||
if (diff44Rate < diff48Rate)
|
||||
- actual_rate = (long)CLK_44EN_RATE;
|
||||
+ actual_rate = (long)clk->clk_rates.clk_44en;
|
||||
else
|
||||
- actual_rate = (long)CLK_48EN_RATE;
|
||||
+ actual_rate = (long)clk->clk_rates.clk_48en;
|
||||
}
|
||||
return actual_rate;
|
||||
}
|
||||
@@ -77,12 +93,12 @@ static long clk_hifiberry_dacpro_round_r
|
||||
static int clk_hifiberry_dacpro_set_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
- unsigned long actual_rate;
|
||||
struct clk_hifiberry_hw *clk = to_hifiberry_clk(hw);
|
||||
+ unsigned long actual_rate;
|
||||
|
||||
actual_rate = (unsigned long)clk_hifiberry_dacpro_round_rate(hw, rate,
|
||||
&parent_rate);
|
||||
- clk->mode = (actual_rate == CLK_44EN_RATE) ? 0 : 1;
|
||||
+ clk->mode = (actual_rate == clk->clk_rates.clk_44en) ? 0 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -95,13 +111,17 @@ const struct clk_ops clk_hifiberry_dacpr
|
||||
|
||||
static int clk_hifiberry_dacpro_probe(struct platform_device *pdev)
|
||||
{
|
||||
- int ret;
|
||||
+ const struct of_device_id *of_id;
|
||||
struct clk_hifiberry_hw *proclk;
|
||||
struct clk *clk;
|
||||
struct device *dev;
|
||||
struct clk_init_data init;
|
||||
+ int ret;
|
||||
|
||||
dev = &pdev->dev;
|
||||
+ of_id = of_match_node(clk_hifiberry_dacpro_dt_ids, dev->of_node);
|
||||
+ if (!of_id)
|
||||
+ return -EINVAL;
|
||||
|
||||
proclk = kzalloc(sizeof(struct clk_hifiberry_hw), GFP_KERNEL);
|
||||
if (!proclk)
|
||||
@@ -115,6 +135,7 @@ static int clk_hifiberry_dacpro_probe(st
|
||||
|
||||
proclk->mode = 0;
|
||||
proclk->hw.init = &init;
|
||||
+ memcpy(&proclk->clk_rates, of_id->data, sizeof(proclk->clk_rates));
|
||||
|
||||
clk = devm_clk_register(dev, &proclk->hw);
|
||||
if (!IS_ERR(clk)) {
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -271,6 +271,7 @@ config SND_BCM2708_SOC_ALLO_BOSS_DAC
|
||||
tristate "Support for Allo Boss DAC"
|
||||
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
+ select COMMON_CLK_HIFIBERRY_DACPRO
|
||||
help
|
||||
Say Y or M if you want to add support for Allo Boss DAC.
|
||||
|
@ -0,0 +1,21 @@
|
||||
From 2addf7045f2b4866ab819f48e4d32f5734a32134 Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Thu, 20 Jul 2023 15:15:27 +0100
|
||||
Subject: [PATCH] fixup! drm/tc358762: Set the pre_enable_upstream_first flag
|
||||
to configure DSI host
|
||||
|
||||
---
|
||||
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
|
||||
@@ -229,7 +229,7 @@ static int tc358762_probe(struct mipi_ds
|
||||
ctx->bridge.funcs = &tc358762_bridge_funcs;
|
||||
ctx->bridge.type = DRM_MODE_CONNECTOR_DPI;
|
||||
ctx->bridge.of_node = dev->of_node;
|
||||
- ctx->bridge.pre_enable_upstream_first = true;
|
||||
+ ctx->bridge.pre_enable_prev_first = true;
|
||||
|
||||
drm_bridge_add(&ctx->bridge);
|
||||
|
@ -0,0 +1,48 @@
|
||||
From b84b8a9ad2046a855a7044b6368def01ddd5de6e Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 21 Jul 2023 16:50:56 +0100
|
||||
Subject: [PATCH] rpi sound cards: Fix Codec Zero rate switching
|
||||
|
||||
The Raspberry Pi Codec Zero (and IQaudIO Codec) don't notify the DA7213
|
||||
codec when it needs to change PLL frequencies. As a result, audio can
|
||||
be played at the wrong rate - play a 48kHz sound immediately after a
|
||||
44.1kHz sound to see the effect, but in some configurations the codec
|
||||
can lock into the wrong state and always get some rates wrong.
|
||||
|
||||
Add the necessary notification to fix the issue.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/bcm/iqaudio-codec.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/sound/soc/bcm/iqaudio-codec.c
|
||||
+++ b/sound/soc/bcm/iqaudio-codec.c
|
||||
@@ -143,6 +143,7 @@ static int snd_rpi_iqaudio_codec_hw_para
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
|
||||
unsigned int samplerate = params_rate(params);
|
||||
|
||||
switch (samplerate) {
|
||||
@@ -152,15 +153,17 @@ static int snd_rpi_iqaudio_codec_hw_para
|
||||
case 48000:
|
||||
case 96000:
|
||||
pll_out = DA7213_PLL_FREQ_OUT_98304000;
|
||||
- return 0;
|
||||
+ break;
|
||||
case 44100:
|
||||
case 88200:
|
||||
pll_out = DA7213_PLL_FREQ_OUT_90316800;
|
||||
- return 0;
|
||||
+ break;
|
||||
default:
|
||||
dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate);
|
||||
return -EINVAL;
|
||||
}
|
||||
+
|
||||
+ return snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0, pll_out);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = {
|
@ -0,0 +1,68 @@
|
||||
From 31822340129e3c4030500d7f30ce4d19bbf9dd40 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 24 Jul 2023 17:34:47 +0100
|
||||
Subject: [PATCH] overlays: Add trickle-voltage-mv parameter to RTCs
|
||||
|
||||
The RV3032 RTC requires an additional DT property to enable trickle
|
||||
charging. Add a parameter - trickle-voltage-mv - to the i2c-rtc
|
||||
and i2c-rtc-gpio overlays to set it.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/5547
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 12 ++++++++----
|
||||
arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi | 2 ++
|
||||
2 files changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -1957,13 +1957,15 @@ Params: abx80x Select o
|
||||
"schottky" (ABx80x and RV1805 only)
|
||||
|
||||
trickle-resistor-ohms Resistor value for trickle charge (DS1339,
|
||||
- ABx80x, RV1805, RV3028)
|
||||
+ ABx80x, BQ32000, RV1805, RV3028, RV3032)
|
||||
+
|
||||
+ trickle-voltage-mv Charge pump voltage for trickle charge (RV3032)
|
||||
|
||||
wakeup-source Specify that the RTC can be used as a wakeup
|
||||
source
|
||||
|
||||
backup-switchover-mode Backup power supply switch mode. Must be 0 for
|
||||
- off or 1 for Vdd < VBackup (RV3028 only)
|
||||
+ off or 1 for Vdd < VBackup (RV3028, RV3032)
|
||||
|
||||
|
||||
Name: i2c-rtc-gpio
|
||||
@@ -2027,13 +2029,15 @@ Params: abx80x Select o
|
||||
"schottky" (ABx80x and RV1805 only)
|
||||
|
||||
trickle-resistor-ohms Resistor value for trickle charge (DS1339,
|
||||
- ABx80x, RV1805, RV3028)
|
||||
+ ABx80x, BQ32000, RV1805, RV3028, RV3032)
|
||||
+
|
||||
+ trickle-voltage-mv Charge pump voltage for trickle charge (RV3032)
|
||||
|
||||
wakeup-source Specify that the RTC can be used as a wakeup
|
||||
source
|
||||
|
||||
backup-switchover-mode Backup power supply switch mode. Must be 0 for
|
||||
- off or 1 for Vdd < VBackup (RV3028 only)
|
||||
+ off or 1 for Vdd < VBackup (RV3028, RV3032)
|
||||
|
||||
i2c_gpio_sda GPIO used for I2C data (default "23")
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
|
||||
+++ b/arch/arm/boot/dts/overlays/i2c-rtc-common.dtsi
|
||||
@@ -339,8 +339,10 @@
|
||||
<&ds1340>,"trickle-resistor-ohms:0",
|
||||
<&abx80x>,"abracon,tc-resistor:0",
|
||||
<&rv3028>,"trickle-resistor-ohms:0",
|
||||
+ <&rv3032>,"trickle-resistor-ohms:0",
|
||||
<&rv1805>,"abracon,tc-resistor:0",
|
||||
<&bq32000>,"abracon,tc-resistor:0";
|
||||
+ trickle-voltage-mv = <&rv3032>,"trickle-voltage-millivolts:0";
|
||||
backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
|
||||
wakeup-source = <&ds1339>,"wakeup-source?",
|
||||
<&ds3231>,"wakeup-source?",
|
@ -0,0 +1,25 @@
|
||||
From 5fb3b300557d6a6902e7321f42fdabb8c09eef54 Mon Sep 17 00:00:00 2001
|
||||
From: Naushir Patuck <naush@raspberrypi.com>
|
||||
Date: Fri, 28 Jul 2023 12:00:40 +0100
|
||||
Subject: [PATCH] drivers: media: imx296: Add standby delay during probe
|
||||
|
||||
Add a 2-5ms delay when coming out of standby and before reading the
|
||||
sensor info register durning probe, as instructed by the datasheet. This
|
||||
standby delay is already present when the sensor starts streaming.
|
||||
|
||||
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
---
|
||||
drivers/media/i2c/imx296.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/media/i2c/imx296.c
|
||||
+++ b/drivers/media/i2c/imx296.c
|
||||
@@ -1022,6 +1022,8 @@ static int imx296_identify_model(struct
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ usleep_range(2000, 5000);
|
||||
+
|
||||
ret = imx296_read(sensor, IMX296_SENSOR_INFO);
|
||||
if (ret < 0) {
|
||||
dev_err(sensor->dev, "failed to read sensor information (%d)\n",
|
@ -0,0 +1,78 @@
|
||||
From e1016d61e3dcb058932e8ec5072f2c4bbb05fcb7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Sun, 30 Jul 2023 18:27:03 +0100
|
||||
Subject: [PATCH] overlays: Add bmp380 to i2c-sensor overlay
|
||||
|
||||
Add support for the BMP380 pressor sensor to the i2c-sensor overlay.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/5558
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 7 +++++--
|
||||
.../boot/dts/overlays/i2c-sensor-common.dtsi | 19 ++++++++++++++++++-
|
||||
2 files changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -2052,8 +2052,8 @@ Info: Adds support for a number of I2C
|
||||
light level and chemical sensors on i2c_arm
|
||||
Load: dtoverlay=i2c-sensor,<param>=<val>
|
||||
Params: addr Set the address for the BH1750, BME280, BME680,
|
||||
- BMP280, CCS811, DS1621, HDC100X, JC42, LM75,
|
||||
- MCP980x, MPU6050, MPU9250, MS5637, MS5803,
|
||||
+ BMP280, BMP380, CCS811, DS1621, HDC100X, JC42,
|
||||
+ LM75, MCP980x, MPU6050, MPU9250, MS5637, MS5803,
|
||||
MS5805, MS5837, MS8607, SHT3x or TMP102
|
||||
|
||||
aht10 Select the Aosong AHT10 temperature and humidity
|
||||
@@ -2075,6 +2075,9 @@ Params: addr Set the
|
||||
bmp280 Select the Bosch Sensortronic BMP280
|
||||
Valid addresses 0x76-0x77, default 0x76
|
||||
|
||||
+ bmp380 Select the Bosch Sensortronic BMP380
|
||||
+ Valid addresses 0x76-0x77, default 0x76
|
||||
+
|
||||
bno055 Select the Bosch Sensortronic BNO055 IMU
|
||||
Valid address 0x28-0x29, default 0x29
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi
|
||||
+++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi
|
||||
@@ -493,11 +493,27 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ fragment@33 {
|
||||
+ target = <&i2cbus>;
|
||||
+ __dormant__ {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ bmp380: bmp380@76 {
|
||||
+ compatible = "bosch,bmp380";
|
||||
+ reg = <0x76>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
__overrides__ {
|
||||
bme280 = <0>,"+0";
|
||||
bmp085 = <0>,"+1";
|
||||
bmp180 = <0>,"+2";
|
||||
bmp280 = <0>,"+3";
|
||||
+ bmp380 = <0>,"+33";
|
||||
htu21 = <0>,"+4";
|
||||
lm75 = <0>,"+5";
|
||||
lm75addr = <&lm75>,"reg:0";
|
||||
@@ -535,7 +551,8 @@
|
||||
<&ms5637>,"reg:0", <&ms5803>,"reg:0", <&ms5805>,"reg:0",
|
||||
<&ms5837>,"reg:0", <&ms8607>,"reg:0",
|
||||
<&mpu6050>,"reg:0", <&mpu9250>,"reg:0",
|
||||
- <&bno055>,"reg:0", <&sht4x>,"reg:0";
|
||||
+ <&bno055>,"reg:0", <&sht4x>,"reg:0",
|
||||
+ <&bmp380>,"reg:0";
|
||||
int_pin = <&max30102>, "interrupts:0",
|
||||
<&mpu6050>, "interrupts:0",
|
||||
<&mpu9250>, "interrupts:0";
|
@ -0,0 +1,162 @@
|
||||
From 4b729a06b15fc5ee3694dcc62346dcb718ae4290 Mon Sep 17 00:00:00 2001
|
||||
From: Oliver Hartkopp <socketcan@hartkopp.net>
|
||||
Date: Sun, 26 Mar 2023 13:59:11 +0200
|
||||
Subject: [PATCH] can: isotp: add module parameter for maximum pdu size
|
||||
|
||||
commit 96d1c81e6a0478535342dff6c730adb076cd84e8 upstream.
|
||||
|
||||
With ISO 15765-2:2016 the PDU size is not limited to 2^12 - 1 (4095)
|
||||
bytes but can be represented as a 32 bit unsigned integer value which
|
||||
allows 2^32 - 1 bytes (~4GB). The use-cases like automotive unified
|
||||
diagnostic services (UDS) and flashing of ECUs still use the small
|
||||
static buffers which are provided at socket creation time.
|
||||
|
||||
When a use-case requires to transfer PDUs up to 1025 kByte the maximum
|
||||
PDU size can now be extended by setting the module parameter
|
||||
max_pdu_size. The extended size buffers are only allocated on a
|
||||
per-socket/connection base when needed at run-time.
|
||||
|
||||
changes since v2: https://lore.kernel.org/all/20230313172510.3851-1-socketcan@hartkopp.net
|
||||
- use ARRAY_SIZE() to reference DEFAULT_MAX_PDU_SIZE only at one place
|
||||
|
||||
changes since v1: https://lore.kernel.org/all/20230311143446.3183-1-socketcan@hartkopp.net
|
||||
- limit the minimum 'max_pdu_size' to 4095 to maintain the classic
|
||||
behavior before ISO 15765-2:2016
|
||||
|
||||
Link: https://github.com/raspberrypi/linux/issues/5371
|
||||
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
|
||||
Link: https://lore.kernel.org/all/20230326115911.15094-1-socketcan@hartkopp.net
|
||||
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
---
|
||||
net/can/isotp.c | 65 ++++++++++++++++++++++++++++++++++++++++++-------
|
||||
1 file changed, 56 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/net/can/isotp.c
|
||||
+++ b/net/can/isotp.c
|
||||
@@ -85,10 +85,21 @@ MODULE_ALIAS("can-proto-6");
|
||||
|
||||
/* ISO 15765-2:2016 supports more than 4095 byte per ISO PDU as the FF_DL can
|
||||
* take full 32 bit values (4 Gbyte). We would need some good concept to handle
|
||||
- * this between user space and kernel space. For now increase the static buffer
|
||||
- * to something about 64 kbyte to be able to test this new functionality.
|
||||
+ * this between user space and kernel space. For now set the static buffer to
|
||||
+ * something about 8 kbyte to be able to test this new functionality.
|
||||
*/
|
||||
-#define MAX_MSG_LENGTH 66000
|
||||
+#define DEFAULT_MAX_PDU_SIZE 8300
|
||||
+
|
||||
+/* maximum PDU size before ISO 15765-2:2016 extension was 4095 */
|
||||
+#define MAX_12BIT_PDU_SIZE 4095
|
||||
+
|
||||
+/* limit the isotp pdu size from the optional module parameter to 1MByte */
|
||||
+#define MAX_PDU_SIZE (1025 * 1024U)
|
||||
+
|
||||
+static unsigned int max_pdu_size __read_mostly = DEFAULT_MAX_PDU_SIZE;
|
||||
+module_param(max_pdu_size, uint, 0444);
|
||||
+MODULE_PARM_DESC(max_pdu_size, "maximum isotp pdu size (default "
|
||||
+ __stringify(DEFAULT_MAX_PDU_SIZE) ")");
|
||||
|
||||
/* N_PCI type values in bits 7-4 of N_PCI bytes */
|
||||
#define N_PCI_SF 0x00 /* single frame */
|
||||
@@ -124,13 +135,15 @@ enum {
|
||||
};
|
||||
|
||||
struct tpcon {
|
||||
- unsigned int idx;
|
||||
+ u8 *buf;
|
||||
+ unsigned int buflen;
|
||||
unsigned int len;
|
||||
+ unsigned int idx;
|
||||
u32 state;
|
||||
u8 bs;
|
||||
u8 sn;
|
||||
u8 ll_dl;
|
||||
- u8 buf[MAX_MSG_LENGTH + 1];
|
||||
+ u8 sbuf[DEFAULT_MAX_PDU_SIZE];
|
||||
};
|
||||
|
||||
struct isotp_sock {
|
||||
@@ -498,7 +511,17 @@ static int isotp_rcv_ff(struct sock *sk,
|
||||
if (so->rx.len + ae + off + ff_pci_sz < so->rx.ll_dl)
|
||||
return 1;
|
||||
|
||||
- if (so->rx.len > MAX_MSG_LENGTH) {
|
||||
+ /* PDU size > default => try max_pdu_size */
|
||||
+ if (so->rx.len > so->rx.buflen && so->rx.buflen < max_pdu_size) {
|
||||
+ u8 *newbuf = kmalloc(max_pdu_size, GFP_ATOMIC);
|
||||
+
|
||||
+ if (newbuf) {
|
||||
+ so->rx.buf = newbuf;
|
||||
+ so->rx.buflen = max_pdu_size;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (so->rx.len > so->rx.buflen) {
|
||||
/* send FC frame with overflow status */
|
||||
isotp_send_fc(sk, ae, ISOTP_FC_OVFLW);
|
||||
return 1;
|
||||
@@ -802,7 +825,7 @@ static void isotp_create_fframe(struct c
|
||||
cf->data[0] = so->opt.ext_address;
|
||||
|
||||
/* create N_PCI bytes with 12/32 bit FF_DL data length */
|
||||
- if (so->tx.len > 4095) {
|
||||
+ if (so->tx.len > MAX_12BIT_PDU_SIZE) {
|
||||
/* use 32 bit FF_DL notation */
|
||||
cf->data[ae] = N_PCI_FF;
|
||||
cf->data[ae + 1] = 0;
|
||||
@@ -939,7 +962,17 @@ static int isotp_sendmsg(struct socket *
|
||||
goto err_event_drop;
|
||||
}
|
||||
|
||||
- if (!size || size > MAX_MSG_LENGTH) {
|
||||
+ /* PDU size > default => try max_pdu_size */
|
||||
+ if (size > so->tx.buflen && so->tx.buflen < max_pdu_size) {
|
||||
+ u8 *newbuf = kmalloc(max_pdu_size, GFP_KERNEL);
|
||||
+
|
||||
+ if (newbuf) {
|
||||
+ so->tx.buf = newbuf;
|
||||
+ so->tx.buflen = max_pdu_size;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!size || size > so->tx.buflen) {
|
||||
err = -EINVAL;
|
||||
goto err_out_drop;
|
||||
}
|
||||
@@ -1194,6 +1227,12 @@ static int isotp_release(struct socket *
|
||||
so->ifindex = 0;
|
||||
so->bound = 0;
|
||||
|
||||
+ if (so->rx.buf != so->rx.sbuf)
|
||||
+ kfree(so->rx.buf);
|
||||
+
|
||||
+ if (so->tx.buf != so->tx.sbuf)
|
||||
+ kfree(so->tx.buf);
|
||||
+
|
||||
sock_orphan(sk);
|
||||
sock->sk = NULL;
|
||||
|
||||
@@ -1588,6 +1627,11 @@ static int isotp_init(struct sock *sk)
|
||||
so->rx.state = ISOTP_IDLE;
|
||||
so->tx.state = ISOTP_IDLE;
|
||||
|
||||
+ so->rx.buf = so->rx.sbuf;
|
||||
+ so->tx.buf = so->tx.sbuf;
|
||||
+ so->rx.buflen = ARRAY_SIZE(so->rx.sbuf);
|
||||
+ so->tx.buflen = ARRAY_SIZE(so->tx.sbuf);
|
||||
+
|
||||
hrtimer_init(&so->rxtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
|
||||
so->rxtimer.function = isotp_rx_timer_handler;
|
||||
hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
|
||||
@@ -1670,7 +1714,10 @@ static __init int isotp_module_init(void
|
||||
{
|
||||
int err;
|
||||
|
||||
- pr_info("can: isotp protocol\n");
|
||||
+ max_pdu_size = max_t(unsigned int, max_pdu_size, MAX_12BIT_PDU_SIZE);
|
||||
+ max_pdu_size = min_t(unsigned int, max_pdu_size, MAX_PDU_SIZE);
|
||||
+
|
||||
+ pr_info("can: isotp protocol (max_pdu_size %d)\n", max_pdu_size);
|
||||
|
||||
err = can_proto_register(&isotp_can_proto);
|
||||
if (err < 0)
|
@ -0,0 +1,40 @@
|
||||
From e1b03ea9e84320e6bf36a1486abaebbceadd7fc7 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Benson <ben.benson@raspberrypi.com>
|
||||
Date: Fri, 21 Jul 2023 15:59:51 +0100
|
||||
Subject: [PATCH] drivers: media: imx296: Updated imx296 driver for external
|
||||
trigger
|
||||
|
||||
Updated imx296 driver to support external trigger mode via XTR pin.
|
||||
Added module parameter to control this mode.
|
||||
|
||||
Signed-off-by: Ben Benson <ben.benson@raspberrypi.com>
|
||||
---
|
||||
drivers/media/i2c/imx296.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/media/i2c/imx296.c
|
||||
+++ b/drivers/media/i2c/imx296.c
|
||||
@@ -20,6 +20,10 @@
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
+static int trigger_mode;
|
||||
+module_param(trigger_mode, int, 0644);
|
||||
+MODULE_PARM_DESC(trigger_mode, "Set trigger mode: 0=default, 1=XTRIG");
|
||||
+
|
||||
#define IMX296_PIXEL_ARRAY_WIDTH 1456
|
||||
#define IMX296_PIXEL_ARRAY_HEIGHT 1088
|
||||
|
||||
@@ -645,6 +649,12 @@ static int imx296_stream_on(struct imx29
|
||||
|
||||
imx296_write(sensor, IMX296_CTRL00, 0, &ret);
|
||||
usleep_range(2000, 5000);
|
||||
+
|
||||
+ if (trigger_mode == 1) {
|
||||
+ imx296_write(sensor, IMX296_CTRL0B, IMX296_CTRL0B_TRIGEN, &ret);
|
||||
+ imx296_write(sensor, IMX296_LOWLAGTRG, IMX296_LOWLAGTRG_FAST, &ret);
|
||||
+ }
|
||||
+
|
||||
imx296_write(sensor, IMX296_CTRL0A, 0, &ret);
|
||||
|
||||
/* vflip and hflip cannot change during streaming */
|
@ -0,0 +1,26 @@
|
||||
From 74bc238e86e62109c74d8f229dc105bf3818b4a7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 2 Aug 2023 14:35:32 +0100
|
||||
Subject: [PATCH] media: dt-bindings: imx258: Fix alternate compatible strings
|
||||
|
||||
Multiple compatible strings must appear as an enum.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
Documentation/devicetree/bindings/media/i2c/imx258.yaml | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/media/i2c/imx258.yaml
|
||||
+++ b/Documentation/devicetree/bindings/media/i2c/imx258.yaml
|
||||
@@ -19,8 +19,9 @@ description: |-
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
- const: sony,imx258
|
||||
- const: sony,imx258-pdaf
|
||||
+ enum:
|
||||
+ - sony,imx258
|
||||
+ - sony,imx258-pdaf
|
||||
|
||||
assigned-clocks: true
|
||||
assigned-clock-parents: true
|
@ -0,0 +1,21 @@
|
||||
From 282819aead0166af415b780241dc2def4caee7f4 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Winkowski <dereference23@outlook.com>
|
||||
Date: Mon, 3 Jul 2023 18:12:01 +0000
|
||||
Subject: [PATCH] char: broadcom: vc_mem: Fix preprocessor conditional
|
||||
|
||||
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
|
||||
---
|
||||
drivers/char/broadcom/vc_mem.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/char/broadcom/vc_mem.c
|
||||
+++ b/drivers/char/broadcom/vc_mem.c
|
||||
@@ -353,7 +353,7 @@ vc_mem_exit(void)
|
||||
pr_debug("%s: called\n", __func__);
|
||||
|
||||
if (vc_mem_inited) {
|
||||
-#if CONFIG_DEBUG_FS
|
||||
+#ifdef CONFIG_DEBUG_FS
|
||||
vc_mem_debugfs_deinit();
|
||||
#endif
|
||||
device_destroy(vc_mem_class, vc_mem_devnum);
|
@ -0,0 +1,32 @@
|
||||
From ec61075a786c455444a1d5df338a41bacfce0bb1 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Winkowski <dereference23@outlook.com>
|
||||
Date: Mon, 3 Jul 2023 18:23:02 +0000
|
||||
Subject: [PATCH] drivers: dwc_otg: Fix fallthrough warnings
|
||||
|
||||
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
|
||||
---
|
||||
drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 1 +
|
||||
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2 +-
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
|
||||
@@ -2049,6 +2049,7 @@ int fiq_fsm_queue_split_transaction(dwc_
|
||||
} else {
|
||||
st->fsm = FIQ_PER_SSPLIT_QUEUED;
|
||||
}
|
||||
+ break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
|
||||
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
|
||||
@@ -402,7 +402,7 @@ int32_t dwc_otg_hcd_handle_rx_status_q_l
|
||||
hc->xfer_count += grxsts.b.bcnt;
|
||||
hc->xfer_buff += grxsts.b.bcnt;
|
||||
}
|
||||
-
|
||||
+ break;
|
||||
case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
|
||||
case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
|
||||
case DWC_GRXSTS_PKTSTS_CH_HALTED:
|
@ -0,0 +1,61 @@
|
||||
From 2dd2f36d10961e3819ff0525ae2567e601973826 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Winkowski <dereference23@outlook.com>
|
||||
Date: Mon, 3 Jul 2023 18:29:37 +0000
|
||||
Subject: [PATCH] vc04_services/vc-sm-cma: Switch one-bit bitfields to bool
|
||||
|
||||
Clang 16 warns:
|
||||
|
||||
../drivers/staging/vc04_services/vc-sm-cma/vc_sm.c:816:19: warning: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Wsingle-bit-bitfield-constant-conversion]
|
||||
buffer->imported = 1;
|
||||
^ ~
|
||||
../drivers/staging/vc04_services/vc-sm-cma/vc_sm.c:822:17: warning: implicit truncation from 'int' to a one-bit wide bit-field changes value from 1 to -1 [-Wsingle-bit-bitfield-constant-conversion]
|
||||
buffer->in_use = 1;
|
||||
^ ~
|
||||
2 warnings generated.
|
||||
|
||||
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
|
||||
---
|
||||
drivers/staging/vc04_services/vc-sm-cma/vc_sm.c | 6 +++---
|
||||
drivers/staging/vc04_services/vc-sm-cma/vc_sm.h | 4 ++--
|
||||
2 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
|
||||
+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
|
||||
@@ -533,7 +533,7 @@ static void vc_sm_dma_buf_release(struct
|
||||
|
||||
pr_debug("%s dmabuf %p, buffer %p\n", __func__, dmabuf, buffer);
|
||||
|
||||
- buffer->in_use = 0;
|
||||
+ buffer->in_use = false;
|
||||
|
||||
/* Unmap on the VPU */
|
||||
vc_sm_vpu_free(buffer);
|
||||
@@ -813,13 +813,13 @@ vc_sm_cma_import_dmabuf_internal(struct
|
||||
buffer->size = import.size;
|
||||
buffer->vpu_state = VPU_MAPPED;
|
||||
|
||||
- buffer->imported = 1;
|
||||
+ buffer->imported = true;
|
||||
buffer->import.dma_buf = dma_buf;
|
||||
|
||||
buffer->import.attach = attach;
|
||||
buffer->import.sgt = sgt;
|
||||
buffer->dma_addr = dma_addr;
|
||||
- buffer->in_use = 1;
|
||||
+ buffer->in_use = true;
|
||||
buffer->kernel_id = import.kernel_id;
|
||||
|
||||
/*
|
||||
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
|
||||
+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
|
||||
@@ -57,8 +57,8 @@ struct vc_sm_buffer {
|
||||
|
||||
char name[VC_SM_MAX_NAME_LEN];
|
||||
|
||||
- int in_use:1; /* Kernel is still using this resource */
|
||||
- int imported:1; /* Imported dmabuf */
|
||||
+ bool in_use:1; /* Kernel is still using this resource */
|
||||
+ bool imported:1; /* Imported dmabuf */
|
||||
|
||||
enum vc_sm_vpu_mapping_state vpu_state;
|
||||
u32 vc_handle; /* VideoCore handle for this buffer */
|
@ -0,0 +1,21 @@
|
||||
From 3333d45347d313ea589b8b8da1193d342060a946 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Winkowski <dereference23@outlook.com>
|
||||
Date: Mon, 3 Jul 2023 18:36:45 +0000
|
||||
Subject: [PATCH] media: i2c: ov2311: Fix uninitialized variable usage
|
||||
|
||||
Signed-off-by: Alexander Winkowski <dereference23@outlook.com>
|
||||
---
|
||||
drivers/media/i2c/ov2311.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/media/i2c/ov2311.c
|
||||
+++ b/drivers/media/i2c/ov2311.c
|
||||
@@ -1018,7 +1018,7 @@ static int ov2311_check_sensor_id(struct
|
||||
struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &ov2311->client->dev;
|
||||
- u32 id = 0, id_msb;
|
||||
+ u32 id = 0, id_msb = 0;
|
||||
int ret;
|
||||
|
||||
ret = ov2311_read_reg(client, OV2311_REG_CHIP_ID + 1,
|
@ -0,0 +1,29 @@
|
||||
From e89e7655a197d28df49da2be7e2003436cf52197 Mon Sep 17 00:00:00 2001
|
||||
From: Ignacio Larrain <ilarrain@gmail.com>
|
||||
Date: Tue, 22 Aug 2023 11:11:56 -0400
|
||||
Subject: [PATCH] drm/panel: Fix default values for Waveshare 7.9 inch DSI
|
||||
touchscreen (#5565)
|
||||
|
||||
This fixes touchscreen calibration, axis swapping and inversion.
|
||||
|
||||
As referenced in https://github.com/raspberrypi/linux/issues/5550
|
||||
---
|
||||
.../dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts
|
||||
@@ -93,10 +93,10 @@
|
||||
<&touch>, "touchscreen-size-x:0=800",
|
||||
<&touch>, "touchscreen-size-y:0=480";
|
||||
7_9_inch = <&panel>, "compatible=waveshare,7.9inch-panel",
|
||||
- <&touch>, "touchscreen-size-x:0=400",
|
||||
- <&touch>, "touchscreen-size-y:0=1280",
|
||||
+ <&touch>, "touchscreen-size-x:0=4096",
|
||||
+ <&touch>, "touchscreen-size-y:0=4096",
|
||||
<&touch>, "touchscreen-inverted-x?",
|
||||
- <&touch>, "touchscreen-inverted-y?";
|
||||
+ <&touch>, "touchscreen-swapped-x-y?";
|
||||
8_0_inch = <&panel>, "compatible=waveshare,8.0inch-panel",
|
||||
<&touch>, "touchscreen-size-x:0=800",
|
||||
<&touch>, "touchscreen-size-y:0=1280",
|
@ -0,0 +1,102 @@
|
||||
From 3fa2fbb7f6e60b85086e454403c5eab1af63b1aa Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 14 Jun 2023 13:43:58 +0100
|
||||
Subject: [PATCH] dtoverlays: Add i2c bus overrides to edt-ft5406 overlay
|
||||
|
||||
Adds the option for the touch controller to be connected to any
|
||||
of the I2C ports.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 17 +++++++++++++++-
|
||||
.../boot/dts/overlays/edt-ft5406-overlay.dts | 20 +++++++++++++++++++
|
||||
arch/arm/boot/dts/overlays/edt-ft5406.dtsi | 9 ++++++++-
|
||||
3 files changed, 44 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -1040,9 +1040,11 @@ Params: dr_mode Dual rol
|
||||
|
||||
|
||||
Name: edt-ft5406
|
||||
-Info: Overlay for the EDT FT5406 touchscreen on the CSI/DSI I2C interface.
|
||||
+Info: Overlay for the EDT FT5406 touchscreen.
|
||||
This works with the Raspberry Pi 7" touchscreen when not being polled
|
||||
by the firmware.
|
||||
+ By default the overlay uses the i2c_csi_dsi I2C interface, but this
|
||||
+ can be overridden
|
||||
You MUST use either "disable_touchscreen=1" or "ignore_lcd=1" in
|
||||
config.txt to stop the firmware polling the touchscreen.
|
||||
Load: dtoverlay=edt-ft5406,<param>=<val>
|
||||
@@ -1051,6 +1053,19 @@ Params: sizex Touchscr
|
||||
invx Touchscreen inverted x axis
|
||||
invy Touchscreen inverted y axis
|
||||
swapxy Touchscreen swapped x y axis
|
||||
+ i2c0 Choose the I2C0 bus on GPIOs 0&1
|
||||
+ i2c1 Choose the I2C1 bus on GPIOs 2&3
|
||||
+ i2c3 Choose the I2C3 bus (configure with the i2c3
|
||||
+ overlay - BCM2711 only)
|
||||
+ i2c4 Choose the I2C4 bus (configure with the i2c4
|
||||
+ overlay - BCM2711 only)
|
||||
+ i2c5 Choose the I2C5 bus (configure with the i2c5
|
||||
+ overlay - BCM2711 only)
|
||||
+ i2c6 Choose the I2C6 bus (configure with the i2c6
|
||||
+ overlay - BCM2711 only)
|
||||
+ addr Sets the address for the touch controller. Note
|
||||
+ that the device must be configured to use the
|
||||
+ specified address.
|
||||
|
||||
|
||||
Name: enc28j60
|
||||
--- a/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/edt-ft5406-overlay.dts
|
||||
@@ -23,4 +23,24 @@
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
+
|
||||
+ __overrides__ {
|
||||
+ i2c0 = <&frag13>,"target:0=",<&i2c0>;
|
||||
+ i2c1 = <&frag13>, "target?=0",
|
||||
+ <&frag13>, "target-path=i2c1",
|
||||
+ <0>,"-0-1";
|
||||
+ i2c3 = <&frag13>, "target?=0",
|
||||
+ <&frag13>, "target-path=i2c3",
|
||||
+ <0>,"-0-1";
|
||||
+ i2c4 = <&frag13>, "target?=0",
|
||||
+ <&frag13>, "target-path=i2c4",
|
||||
+ <0>,"-0-1";
|
||||
+ i2c5 = <&frag13>, "target?=0",
|
||||
+ <&frag13>, "target-path=i2c5",
|
||||
+ <0>,"-0-1";
|
||||
+ i2c6 = <&frag13>, "target?=0",
|
||||
+ <&frag13>, "target-path=i2c6",
|
||||
+ <0>,"-0-1";
|
||||
+ addr = <&ft5406>,"reg:0";
|
||||
+ };
|
||||
};
|
||||
--- a/arch/arm/boot/dts/overlays/edt-ft5406.dtsi
|
||||
+++ b/arch/arm/boot/dts/overlays/edt-ft5406.dtsi
|
||||
@@ -23,7 +23,7 @@
|
||||
};
|
||||
|
||||
fragment@12 {
|
||||
- target = <&i2c_csi_dsi>;
|
||||
+ target = <&i2cbus>;
|
||||
__overlay__ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
@@ -37,6 +37,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ frag13: fragment@13 {
|
||||
+ target = <&i2c_csi_dsi>;
|
||||
+ i2cbus: __overlay__ {
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
__overrides__ {
|
||||
sizex = <&ft5406>,"touchscreen-size-x:0";
|
||||
sizey = <&ft5406>,"touchscreen-size-y:0";
|
@ -0,0 +1,25 @@
|
||||
From 9d9586dc0c0deecb90675bd70862fe262f7376ab Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 14 Jun 2023 14:25:21 +0100
|
||||
Subject: [PATCH] dtoverlays: Fix README text for i2c-fan
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -1800,10 +1800,10 @@ Params: addr Sets the
|
||||
i2c3 Choose the I2C3 bus (configure with the i2c3
|
||||
overlay - BCM2711 only)
|
||||
|
||||
- i2c4 Choose the I2C3 bus (configure with the i2c3
|
||||
+ i2c4 Choose the I2C4 bus (configure with the i2c4
|
||||
overlay - BCM2711 only)
|
||||
|
||||
- i2c5 Choose the I2C5 bus (configure with the i2c4
|
||||
+ i2c5 Choose the I2C5 bus (configure with the i2c5
|
||||
overlay - BCM2711 only)
|
||||
|
||||
i2c6 Choose the I2C6 bus (configure with the i2c6
|
@ -0,0 +1,50 @@
|
||||
From e804bd1843236a63815e9acfb1a38ebf9a28ef5b Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Thu, 31 Aug 2023 16:45:44 +0100
|
||||
Subject: [PATCH] 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>
|
||||
---
|
||||
drivers/irqchip/irq-bcm2835.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -343,7 +343,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);
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
From 5e54398e1b61335883dff1be46a6c8b3ca973926 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 30 Aug 2023 18:03:37 +0100
|
||||
Subject: [PATCH] dtoverlays: Add drm option to piscreen overlay
|
||||
|
||||
Adds the option of selecting the DRM/KMS TinyDRM driver for
|
||||
this panel, rather than the deprecated FBTFT one.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/README | 3 +++
|
||||
arch/arm/boot/dts/overlays/piscreen-overlay.dts | 10 +++++++---
|
||||
2 files changed, 10 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -3245,6 +3245,9 @@ Params: speed Display
|
||||
|
||||
xohms Touchpanel sensitivity (X-plate resistance)
|
||||
|
||||
+ drm Select the DRM/KMS driver instead of the FBTFT
|
||||
+ one
|
||||
+
|
||||
|
||||
Name: piscreen2r
|
||||
Info: PiScreen 2 with resistive TP display by OzzMaker.com
|
||||
--- a/arch/arm/boot/dts/overlays/piscreen-overlay.dts
|
||||
+++ b/arch/arm/boot/dts/overlays/piscreen-overlay.dts
|
||||
@@ -6,6 +6,8 @@
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
/ {
|
||||
compatible = "brcm,bcm2835";
|
||||
|
||||
@@ -59,9 +61,9 @@
|
||||
fps = <30>;
|
||||
buswidth = <8>;
|
||||
regwidth = <16>;
|
||||
- reset-gpios = <&gpio 25 1>;
|
||||
- dc-gpios = <&gpio 24 0>;
|
||||
- led-gpios = <&gpio 22 0>;
|
||||
+ reset-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
|
||||
+ dc-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>;
|
||||
+ led-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>;
|
||||
debug = <0>;
|
||||
|
||||
init = <0x10000b0 0x00
|
||||
@@ -98,5 +100,7 @@
|
||||
fps = <&piscreen>,"fps:0";
|
||||
debug = <&piscreen>,"debug:0";
|
||||
xohms = <&piscreen_ts>,"ti,x-plate-ohms;0";
|
||||
+ drm = <&piscreen>,"compatible=waveshare,rpi-lcd-35",
|
||||
+ <&piscreen>,"reset-gpios:8=",<GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
@ -0,0 +1,36 @@
|
||||
From f59fe2d1bd056af117eb512bb0e9210a943c6d47 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Fri, 1 Sep 2023 12:17:38 +0100
|
||||
Subject: [PATCH] drm/ili9486: Resolve clash in spi_device_id names
|
||||
|
||||
For "Really Good Reasons" [1] the SPI core requires a match
|
||||
between compatible device strings and the name in spi_device_id.
|
||||
|
||||
The ili9486 driver uses compatible strings "waveshare,rpi-lcd-35"
|
||||
and "ozzmaker,piscreen", but "rpi-lcd-35" and "piscreen" are missing,
|
||||
so add them.
|
||||
|
||||
Compatible string "ilitek,ili9486" is already used by
|
||||
staging/fbtft/fb_ili9486, therefore leaving it present in ili9486 as an
|
||||
spi_device_id causes the incorrect module to be loaded, therefore remove
|
||||
this id.
|
||||
|
||||
[1] https://elixir.bootlin.com/linux/latest/source/drivers/spi/spi.c#L487
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/tiny/ili9486.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpu/drm/tiny/ili9486.c
|
||||
+++ b/drivers/gpu/drm/tiny/ili9486.c
|
||||
@@ -187,7 +187,8 @@ static const struct of_device_id ili9486
|
||||
MODULE_DEVICE_TABLE(of, ili9486_of_match);
|
||||
|
||||
static const struct spi_device_id ili9486_id[] = {
|
||||
- { "ili9486", 0 },
|
||||
+ { "rpi-lcd-35", 0 },
|
||||
+ { "piscreen", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ili9486_id);
|
@ -0,0 +1,50 @@
|
||||
From 50c5a8558f4aaa54a3c4f5a8c2b6053f641d94eb Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Fri, 1 Sep 2023 12:23:30 +0100
|
||||
Subject: [PATCH] input: ads7846: Add missing spi_device_id strings
|
||||
|
||||
The SPI core logs error messages if a compatible string device
|
||||
name is not also present as an spi_device_id.
|
||||
|
||||
No spi_device_id values are specified by the driver, therefore
|
||||
we get 4 log lines every time it is loaded:
|
||||
SPI driver ads7846 has no spi_device_id for ti,tsc2046
|
||||
SPI driver ads7846 has no spi_device_id for ti,ads7843
|
||||
SPI driver ads7846 has no spi_device_id for ti,ads7845
|
||||
SPI driver ads7846 has no spi_device_id for ti,ads7873
|
||||
|
||||
Add the spi_device_id values for these devices.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
drivers/input/touchscreen/ads7846.c | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
--- a/drivers/input/touchscreen/ads7846.c
|
||||
+++ b/drivers/input/touchscreen/ads7846.c
|
||||
@@ -1127,6 +1127,17 @@ static const struct of_device_id ads7846
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads7846_dt_ids);
|
||||
|
||||
+static const struct spi_device_id ads7846_spi_ids[] = {
|
||||
+ { "tsc2046", 0 },
|
||||
+ { "ads7843", 0 },
|
||||
+ { "ads7843", 0 },
|
||||
+ { "ads7845", 0 },
|
||||
+ { "ads7846", 0 },
|
||||
+ { "ads7873", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(spi, ads7846_spi_ids);
|
||||
+
|
||||
static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
|
||||
{
|
||||
struct ads7846_platform_data *pdata;
|
||||
@@ -1424,6 +1435,7 @@ static struct spi_driver ads7846_driver
|
||||
.pm = &ads7846_pm,
|
||||
.of_match_table = of_match_ptr(ads7846_dt_ids),
|
||||
},
|
||||
+ .id_table = ads7846_spi_ids,
|
||||
.probe = ads7846_probe,
|
||||
.remove = ads7846_remove,
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
From 65742d7116e89b08858fcd7d67bd521ee19ee837 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
Date: Wed, 30 Aug 2023 18:05:43 +0100
|
||||
Subject: [PATCH] staging: bcm2835-codec: Downgrade the level for a debug
|
||||
message
|
||||
|
||||
The debug message from bcm2835_codec_buf_prepare when the buffer
|
||||
size is incorrect can be a little spammy if the application isn't
|
||||
careful on how it drives it, therefore drop the priority of the
|
||||
message.
|
||||
|
||||
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
|
||||
---
|
||||
.../staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
|
||||
+++ b/drivers/staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c
|
||||
@@ -2883,7 +2883,7 @@ static int bcm2835_codec_buf_prepare(str
|
||||
}
|
||||
|
||||
if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
|
||||
- v4l2_err(&ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n",
|
||||
+ v4l2_dbg(1, debug, &ctx->dev->v4l2_dev, "%s data will not fit into plane (%lu < %lu)\n",
|
||||
__func__, vb2_plane_size(vb, 0),
|
||||
(long)q_data->sizeimage);
|
||||
return -EINVAL;
|
@ -0,0 +1,286 @@
|
||||
From cee471c3ada3215d6dfc53fb0f1b97548444dea7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 5 Sep 2023 11:56:19 +0100
|
||||
Subject: [PATCH] gpio-fsm: Sort functions into a more logical order
|
||||
|
||||
Move some functions into a more logical ordering. This change causes
|
||||
no functional change and is essentially cosmetic.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/gpio/gpio-fsm.c | 245 ++++++++++++++++++++--------------------
|
||||
1 file changed, 125 insertions(+), 120 deletions(-)
|
||||
|
||||
--- a/drivers/gpio/gpio-fsm.c
|
||||
+++ b/drivers/gpio/gpio-fsm.c
|
||||
@@ -193,131 +193,14 @@ static void free_symbols(struct symtab_e
|
||||
}
|
||||
}
|
||||
|
||||
-static int gpio_fsm_get_direction(struct gpio_chip *gc, unsigned int off)
|
||||
-{
|
||||
- struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
- struct soft_gpio *sg;
|
||||
-
|
||||
- if (off >= gf->num_soft_gpios)
|
||||
- return -EINVAL;
|
||||
- sg = &gf->soft_gpios[off];
|
||||
-
|
||||
- return sg->dir;
|
||||
-}
|
||||
-
|
||||
-static int gpio_fsm_get(struct gpio_chip *gc, unsigned int off)
|
||||
-{
|
||||
- struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
- struct soft_gpio *sg;
|
||||
-
|
||||
- if (off >= gf->num_soft_gpios)
|
||||
- return -EINVAL;
|
||||
- sg = &gf->soft_gpios[off];
|
||||
-
|
||||
- return sg->value;
|
||||
-}
|
||||
-
|
||||
static void gpio_fsm_go_to_state(struct gpio_fsm *gf,
|
||||
- struct fsm_state *new_state)
|
||||
-{
|
||||
- struct input_gpio_state *inp_state;
|
||||
- struct gpio_event *gp_ev;
|
||||
- struct fsm_state *state;
|
||||
- int i;
|
||||
-
|
||||
- dev_dbg(gf->dev, "go_to_state(%s)\n",
|
||||
- new_state ? new_state->name : "<unset>");
|
||||
-
|
||||
- spin_lock(&gf->spinlock);
|
||||
-
|
||||
- if (gf->next_state) {
|
||||
- /* Something else has already requested a transition */
|
||||
- spin_unlock(&gf->spinlock);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- gf->next_state = new_state;
|
||||
- state = gf->current_state;
|
||||
- gf->delay_target_state = NULL;
|
||||
-
|
||||
- if (state) {
|
||||
- /* Disarm any GPIO IRQs */
|
||||
- for (i = 0; i < state->num_gpio_events; i++) {
|
||||
- gp_ev = &state->gpio_events[i];
|
||||
- inp_state = &gf->input_gpio_states[gp_ev->index];
|
||||
- inp_state->target = NULL;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- spin_unlock(&gf->spinlock);
|
||||
-
|
||||
- if (new_state)
|
||||
- schedule_work(&gf->work);
|
||||
-}
|
||||
+ struct fsm_state *new_state);
|
||||
|
||||
static void gpio_fsm_set_soft(struct gpio_fsm *gf,
|
||||
- unsigned int off, int val)
|
||||
-{
|
||||
- struct soft_gpio *sg = &gf->soft_gpios[off];
|
||||
- struct gpio_event *gp_ev;
|
||||
- struct fsm_state *state;
|
||||
- int i;
|
||||
-
|
||||
- dev_dbg(gf->dev, "set(%d,%d)\n", off, val);
|
||||
- state = gf->current_state;
|
||||
- sg->value = val;
|
||||
- for (i = 0; i < state->num_soft_events; i++) {
|
||||
- gp_ev = &state->soft_events[i];
|
||||
- if (gp_ev->index == off && gp_ev->value == val) {
|
||||
- if (gf->debug)
|
||||
- dev_info(gf->dev,
|
||||
- "GF_SOFT %d->%d -> %s\n", gp_ev->index,
|
||||
- gp_ev->value, gp_ev->target->name);
|
||||
- gpio_fsm_go_to_state(gf, gp_ev->target);
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static int gpio_fsm_direction_input(struct gpio_chip *gc, unsigned int off)
|
||||
-{
|
||||
- struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
- struct soft_gpio *sg;
|
||||
-
|
||||
- if (off >= gf->num_soft_gpios)
|
||||
- return -EINVAL;
|
||||
- sg = &gf->soft_gpios[off];
|
||||
- sg->dir = GPIOF_DIR_IN;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int gpio_fsm_direction_output(struct gpio_chip *gc, unsigned int off,
|
||||
- int value)
|
||||
-{
|
||||
- struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
- struct soft_gpio *sg;
|
||||
-
|
||||
- if (off >= gf->num_soft_gpios)
|
||||
- return -EINVAL;
|
||||
- sg = &gf->soft_gpios[off];
|
||||
- sg->dir = GPIOF_DIR_OUT;
|
||||
- gpio_fsm_set_soft(gf, off, value);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void gpio_fsm_set(struct gpio_chip *gc, unsigned int off, int val)
|
||||
-{
|
||||
- struct gpio_fsm *gf;
|
||||
-
|
||||
- gf = gpiochip_get_data(gc);
|
||||
- if (off < gf->num_soft_gpios)
|
||||
- gpio_fsm_set_soft(gf, off, val);
|
||||
-}
|
||||
+ unsigned int off, int val);
|
||||
|
||||
static void gpio_fsm_enter_state(struct gpio_fsm *gf,
|
||||
- struct fsm_state *state)
|
||||
+ struct fsm_state *state)
|
||||
{
|
||||
struct input_gpio_state *inp_state;
|
||||
struct output_signal *signal;
|
||||
@@ -431,6 +314,44 @@ static void gpio_fsm_enter_state(struct
|
||||
}
|
||||
}
|
||||
|
||||
+static void gpio_fsm_go_to_state(struct gpio_fsm *gf,
|
||||
+ struct fsm_state *new_state)
|
||||
+{
|
||||
+ struct input_gpio_state *inp_state;
|
||||
+ struct gpio_event *gp_ev;
|
||||
+ struct fsm_state *state;
|
||||
+ int i;
|
||||
+
|
||||
+ dev_dbg(gf->dev, "go_to_state(%s)\n",
|
||||
+ new_state ? new_state->name : "<unset>");
|
||||
+
|
||||
+ spin_lock(&gf->spinlock);
|
||||
+
|
||||
+ if (gf->next_state) {
|
||||
+ /* Something else has already requested a transition */
|
||||
+ spin_unlock(&gf->spinlock);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ gf->next_state = new_state;
|
||||
+ state = gf->current_state;
|
||||
+ gf->delay_target_state = NULL;
|
||||
+
|
||||
+ if (state) {
|
||||
+ /* Disarm any GPIO IRQs */
|
||||
+ for (i = 0; i < state->num_gpio_events; i++) {
|
||||
+ gp_ev = &state->gpio_events[i];
|
||||
+ inp_state = &gf->input_gpio_states[gp_ev->index];
|
||||
+ inp_state->target = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock(&gf->spinlock);
|
||||
+
|
||||
+ if (new_state)
|
||||
+ schedule_work(&gf->work);
|
||||
+}
|
||||
+
|
||||
static void gpio_fsm_work(struct work_struct *work)
|
||||
{
|
||||
struct input_gpio_state *inp_state;
|
||||
@@ -851,6 +772,90 @@ static int resolve_sym_to_state(struct g
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void gpio_fsm_set_soft(struct gpio_fsm *gf,
|
||||
+ unsigned int off, int val)
|
||||
+{
|
||||
+ struct soft_gpio *sg = &gf->soft_gpios[off];
|
||||
+ struct gpio_event *gp_ev;
|
||||
+ struct fsm_state *state;
|
||||
+ int i;
|
||||
+
|
||||
+ dev_dbg(gf->dev, "set(%d,%d)\n", off, val);
|
||||
+ state = gf->current_state;
|
||||
+ sg->value = val;
|
||||
+ for (i = 0; i < state->num_soft_events; i++) {
|
||||
+ gp_ev = &state->soft_events[i];
|
||||
+ if (gp_ev->index == off && gp_ev->value == val) {
|
||||
+ if (gf->debug)
|
||||
+ dev_info(gf->dev,
|
||||
+ "GF_SOFT %d->%d -> %s\n", gp_ev->index,
|
||||
+ gp_ev->value, gp_ev->target->name);
|
||||
+ gpio_fsm_go_to_state(gf, gp_ev->target);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int gpio_fsm_get(struct gpio_chip *gc, unsigned int off)
|
||||
+{
|
||||
+ struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
+ struct soft_gpio *sg;
|
||||
+
|
||||
+ if (off >= gf->num_soft_gpios)
|
||||
+ return -EINVAL;
|
||||
+ sg = &gf->soft_gpios[off];
|
||||
+
|
||||
+ return sg->value;
|
||||
+}
|
||||
+
|
||||
+static void gpio_fsm_set(struct gpio_chip *gc, unsigned int off, int val)
|
||||
+{
|
||||
+ struct gpio_fsm *gf;
|
||||
+
|
||||
+ gf = gpiochip_get_data(gc);
|
||||
+ if (off < gf->num_soft_gpios)
|
||||
+ gpio_fsm_set_soft(gf, off, val);
|
||||
+}
|
||||
+
|
||||
+static int gpio_fsm_get_direction(struct gpio_chip *gc, unsigned int off)
|
||||
+{
|
||||
+ struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
+ struct soft_gpio *sg;
|
||||
+
|
||||
+ if (off >= gf->num_soft_gpios)
|
||||
+ return -EINVAL;
|
||||
+ sg = &gf->soft_gpios[off];
|
||||
+
|
||||
+ return sg->dir;
|
||||
+}
|
||||
+
|
||||
+static int gpio_fsm_direction_input(struct gpio_chip *gc, unsigned int off)
|
||||
+{
|
||||
+ struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
+ struct soft_gpio *sg;
|
||||
+
|
||||
+ if (off >= gf->num_soft_gpios)
|
||||
+ return -EINVAL;
|
||||
+ sg = &gf->soft_gpios[off];
|
||||
+ sg->dir = GPIOF_DIR_IN;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gpio_fsm_direction_output(struct gpio_chip *gc, unsigned int off,
|
||||
+ int value)
|
||||
+{
|
||||
+ struct gpio_fsm *gf = gpiochip_get_data(gc);
|
||||
+ struct soft_gpio *sg;
|
||||
+
|
||||
+ if (off >= gf->num_soft_gpios)
|
||||
+ return -EINVAL;
|
||||
+ sg = &gf->soft_gpios[off];
|
||||
+ sg->dir = GPIOF_DIR_OUT;
|
||||
+ gpio_fsm_set_soft(gf, off, value);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
/*
|
||||
* /sys/class/gpio-fsm/<fsm-name>/
|
@ -0,0 +1,192 @@
|
||||
From f0061ffc98c6e027c5774e2a24ceadcfee4167ea Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 5 Sep 2023 12:01:13 +0100
|
||||
Subject: [PATCH] gpio_fsm: Rework the atomic-vs-non-atomic split
|
||||
|
||||
Partition the code to separate atomic and non-atomic methods so that
|
||||
none of them have to handle both cases. The result avoids using deferred
|
||||
work unless necessary, and should be easier to understand.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/gpio/gpio-fsm.c | 84 ++++++++++++++++++++---------------------
|
||||
1 file changed, 41 insertions(+), 43 deletions(-)
|
||||
|
||||
--- a/drivers/gpio/gpio-fsm.c
|
||||
+++ b/drivers/gpio/gpio-fsm.c
|
||||
@@ -193,9 +193,6 @@ static void free_symbols(struct symtab_e
|
||||
}
|
||||
}
|
||||
|
||||
-static void gpio_fsm_go_to_state(struct gpio_fsm *gf,
|
||||
- struct fsm_state *new_state);
|
||||
-
|
||||
static void gpio_fsm_set_soft(struct gpio_fsm *gf,
|
||||
unsigned int off, int val);
|
||||
|
||||
@@ -213,6 +210,7 @@ static void gpio_fsm_enter_state(struct
|
||||
dev_dbg(gf->dev, "enter_state(%s)\n", state->name);
|
||||
|
||||
gf->current_state = state;
|
||||
+ gf->delay_target_state = NULL;
|
||||
|
||||
// 1. Apply any listed signals
|
||||
for (i = 0; i < state->num_signals; i++) {
|
||||
@@ -271,7 +269,7 @@ static void gpio_fsm_enter_state(struct
|
||||
dev_info(gf->dev,
|
||||
"GF_SOFT %d=%d -> %s\n", event->index,
|
||||
event->value, event->target->name);
|
||||
- gpio_fsm_go_to_state(gf, event->target);
|
||||
+ gpio_fsm_enter_state(gf, event->target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -284,7 +282,7 @@ static void gpio_fsm_enter_state(struct
|
||||
inp_state->value = event->value;
|
||||
inp_state->enabled = true;
|
||||
|
||||
- value = gpiod_get_value(gf->input_gpios->desc[event->index]);
|
||||
+ value = gpiod_get_value_cansleep(gf->input_gpios->desc[event->index]);
|
||||
|
||||
// Clear stale event state
|
||||
disable_irq(inp_state->irq);
|
||||
@@ -299,7 +297,7 @@ static void gpio_fsm_enter_state(struct
|
||||
dev_info(gf->dev,
|
||||
"GF_IN %d=%d -> %s\n", event->index,
|
||||
event->value, event->target->name);
|
||||
- gpio_fsm_go_to_state(gf, event->target);
|
||||
+ gpio_fsm_enter_state(gf, event->target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -325,6 +323,33 @@ static void gpio_fsm_go_to_state(struct
|
||||
dev_dbg(gf->dev, "go_to_state(%s)\n",
|
||||
new_state ? new_state->name : "<unset>");
|
||||
|
||||
+ state = gf->current_state;
|
||||
+
|
||||
+ /* Disable any enabled GPIO IRQs */
|
||||
+ for (i = 0; i < state->num_gpio_events; i++) {
|
||||
+ gp_ev = &state->gpio_events[i];
|
||||
+ inp_state = &gf->input_gpio_states[gp_ev->index];
|
||||
+ if (inp_state->enabled) {
|
||||
+ inp_state->enabled = false;
|
||||
+ irq_set_irq_type(inp_state->irq,
|
||||
+ IRQF_TRIGGER_NONE);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ gpio_fsm_enter_state(gf, new_state);
|
||||
+}
|
||||
+
|
||||
+static void gpio_fsm_go_to_state_deferred(struct gpio_fsm *gf,
|
||||
+ struct fsm_state *new_state)
|
||||
+{
|
||||
+ struct input_gpio_state *inp_state;
|
||||
+ struct gpio_event *gp_ev;
|
||||
+ struct fsm_state *state;
|
||||
+ int i;
|
||||
+
|
||||
+ dev_dbg(gf->dev, "go_to_state_deferred(%s)\n",
|
||||
+ new_state ? new_state->name : "<unset>");
|
||||
+
|
||||
spin_lock(&gf->spinlock);
|
||||
|
||||
if (gf->next_state) {
|
||||
@@ -335,57 +360,31 @@ static void gpio_fsm_go_to_state(struct
|
||||
|
||||
gf->next_state = new_state;
|
||||
state = gf->current_state;
|
||||
- gf->delay_target_state = NULL;
|
||||
|
||||
- if (state) {
|
||||
- /* Disarm any GPIO IRQs */
|
||||
- for (i = 0; i < state->num_gpio_events; i++) {
|
||||
- gp_ev = &state->gpio_events[i];
|
||||
- inp_state = &gf->input_gpio_states[gp_ev->index];
|
||||
- inp_state->target = NULL;
|
||||
- }
|
||||
+ /* Disarm any GPIO IRQs */
|
||||
+ for (i = 0; i < state->num_gpio_events; i++) {
|
||||
+ gp_ev = &state->gpio_events[i];
|
||||
+ inp_state = &gf->input_gpio_states[gp_ev->index];
|
||||
+ inp_state->target = NULL;
|
||||
}
|
||||
|
||||
spin_unlock(&gf->spinlock);
|
||||
|
||||
- if (new_state)
|
||||
- schedule_work(&gf->work);
|
||||
+ schedule_work(&gf->work);
|
||||
}
|
||||
|
||||
static void gpio_fsm_work(struct work_struct *work)
|
||||
{
|
||||
- struct input_gpio_state *inp_state;
|
||||
struct fsm_state *new_state;
|
||||
- struct fsm_state *state;
|
||||
- struct gpio_event *gp_ev;
|
||||
struct gpio_fsm *gf;
|
||||
- int i;
|
||||
|
||||
gf = container_of(work, struct gpio_fsm, work);
|
||||
spin_lock(&gf->spinlock);
|
||||
- state = gf->current_state;
|
||||
new_state = gf->next_state;
|
||||
- if (!new_state)
|
||||
- new_state = gf->delay_target_state;
|
||||
gf->next_state = NULL;
|
||||
- gf->delay_target_state = NULL;
|
||||
spin_unlock(&gf->spinlock);
|
||||
|
||||
- if (state) {
|
||||
- /* Disable any enabled GPIO IRQs */
|
||||
- for (i = 0; i < state->num_gpio_events; i++) {
|
||||
- gp_ev = &state->gpio_events[i];
|
||||
- inp_state = &gf->input_gpio_states[gp_ev->index];
|
||||
- if (inp_state->enabled) {
|
||||
- inp_state->enabled = false;
|
||||
- irq_set_irq_type(inp_state->irq,
|
||||
- IRQF_TRIGGER_NONE);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (new_state)
|
||||
- gpio_fsm_enter_state(gf, new_state);
|
||||
+ gpio_fsm_go_to_state(gf, new_state);
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_fsm_gpio_irq_handler(int irq, void *dev_id)
|
||||
@@ -404,7 +403,7 @@ static irqreturn_t gpio_fsm_gpio_irq_han
|
||||
if (gf->debug)
|
||||
dev_info(gf->dev, "GF_IN %d->%d -> %s\n",
|
||||
inp_state->index, inp_state->value, target->name);
|
||||
- gpio_fsm_go_to_state(gf, target);
|
||||
+ gpio_fsm_go_to_state_deferred(gf, target);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -416,12 +415,11 @@ static void gpio_fsm_timer(struct timer_
|
||||
target = gf->delay_target_state;
|
||||
if (!target)
|
||||
return;
|
||||
-
|
||||
if (gf->debug)
|
||||
dev_info(gf->dev, "GF_DELAY %d -> %s\n", gf->delay_ms,
|
||||
target->name);
|
||||
|
||||
- gpio_fsm_go_to_state(gf, target);
|
||||
+ gpio_fsm_go_to_state_deferred(gf, target);
|
||||
}
|
||||
|
||||
int gpio_fsm_parse_signals(struct gpio_fsm *gf, struct fsm_state *state,
|
||||
@@ -1119,7 +1117,7 @@ static int gpio_fsm_probe(struct platfor
|
||||
if (gf->debug)
|
||||
dev_info(gf->dev, "Start -> %s\n", gf->start_state->name);
|
||||
|
||||
- gpio_fsm_go_to_state(gf, gf->start_state);
|
||||
+ gpio_fsm_enter_state(gf, gf->start_state);
|
||||
|
||||
return devm_gpiochip_add_data(dev, &gf->gc, gf);
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
From bf9fb25f3265605572f04e5c7836bb83ee345236 Mon Sep 17 00:00:00 2001
|
||||
From: Chao Yu <chao@kernel.org>
|
||||
Date: Fri, 30 Dec 2022 23:43:32 +0800
|
||||
Subject: [PATCH] f2fs: fix to avoid NULL pointer dereference in
|
||||
f2fs_issue_flush()
|
||||
|
||||
commit b3d83066cbebc76dbac8a5fca931f64b4c6fff34 upstream.
|
||||
|
||||
With below two cases, it will cause NULL pointer dereference when
|
||||
accessing SM_I(sbi)->fcc_info in f2fs_issue_flush().
|
||||
|
||||
a) If kthread_run() fails in f2fs_create_flush_cmd_control(), it will
|
||||
release SM_I(sbi)->fcc_info,
|
||||
|
||||
- mount -o noflush_merge /dev/vda /mnt/f2fs
|
||||
- mount -o remount,flush_merge /dev/vda /mnt/f2fs -- kthread_run() fails
|
||||
- dd if=/dev/zero of=/mnt/f2fs/file bs=4k count=1 conv=fsync
|
||||
|
||||
b) we will never allocate memory for SM_I(sbi)->fcc_info w/ below
|
||||
testcase,
|
||||
|
||||
- mount -o ro /dev/vda /mnt/f2fs
|
||||
- mount -o rw,remount /dev/vda /mnt/f2fs
|
||||
- dd if=/dev/zero of=/mnt/f2fs/file bs=4k count=1 conv=fsync
|
||||
|
||||
In order to fix this issue, let change as below:
|
||||
- fix error path handling in f2fs_create_flush_cmd_control().
|
||||
- allocate SM_I(sbi)->fcc_info even if readonly is on.
|
||||
|
||||
Signed-off-by: Chao Yu <chao@kernel.org>
|
||||
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
||||
---
|
||||
fs/f2fs/segment.c | 12 ++++--------
|
||||
1 file changed, 4 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/fs/f2fs/segment.c
|
||||
+++ b/fs/f2fs/segment.c
|
||||
@@ -663,9 +663,7 @@ init_thread:
|
||||
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(fcc->f2fs_issue_flush)) {
|
||||
err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||
- kfree(fcc);
|
||||
- SM_I(sbi)->fcc_info = NULL;
|
||||
- return err;
|
||||
+ fcc->f2fs_issue_flush = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
@@ -5062,11 +5060,9 @@ int f2fs_build_segment_manager(struct f2
|
||||
|
||||
init_f2fs_rwsem(&sm_info->curseg_lock);
|
||||
|
||||
- if (!f2fs_readonly(sbi->sb)) {
|
||||
- err = f2fs_create_flush_cmd_control(sbi);
|
||||
- if (err)
|
||||
- return err;
|
||||
- }
|
||||
+ err = f2fs_create_flush_cmd_control(sbi);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
|
||||
err = create_discard_cmd_control(sbi);
|
||||
if (err)
|
@ -1,4 +1,4 @@
|
||||
From b642f64d629df5515f3a01fc5b2e17c3fa7b404c Mon Sep 17 00:00:00 2001
|
||||
From e079555a4c68356e58249cfc041b28f6eb455bd5 Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Wahren <wahrenst@gmx.net>
|
||||
Date: Sat, 4 May 2019 17:06:15 +0200
|
||||
Subject: [PATCH] hwrng: iproc-rng200: Add BCM2838 support
|
||||
@ -17,8 +17,8 @@ Fixes: "hwrng: iproc-rng200: Add BCM2838 support"
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/char/hw_random/Kconfig | 2 +-
|
||||
drivers/char/hw_random/iproc-rng200.c | 78 +++++++++++++++++++++++++--
|
||||
2 files changed, 76 insertions(+), 4 deletions(-)
|
||||
drivers/char/hw_random/iproc-rng200.c | 79 ++++++++++++++++++++++++++-
|
||||
2 files changed, 77 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/char/hw_random/Kconfig
|
||||
+++ b/drivers/char/hw_random/Kconfig
|
||||
@ -33,7 +33,15 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
module will be called iproc-rng200
|
||||
--- a/drivers/char/hw_random/iproc-rng200.c
|
||||
+++ b/drivers/char/hw_random/iproc-rng200.c
|
||||
@@ -21,6 +21,7 @@
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
@@ -21,6 +22,7 @@
|
||||
#define RNG_CTRL_OFFSET 0x00
|
||||
#define RNG_CTRL_RNG_RBGEN_MASK 0x00001FFF
|
||||
#define RNG_CTRL_RNG_RBGEN_ENABLE 0x00000001
|
||||
@ -41,7 +49,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
#define RNG_SOFT_RESET_OFFSET 0x04
|
||||
#define RNG_SOFT_RESET 0x00000001
|
||||
@@ -28,16 +29,23 @@
|
||||
@@ -28,16 +30,23 @@
|
||||
#define RBG_SOFT_RESET_OFFSET 0x08
|
||||
#define RBG_SOFT_RESET 0x00000001
|
||||
|
||||
@ -65,7 +73,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
struct iproc_rng200_dev {
|
||||
struct hwrng rng;
|
||||
@@ -158,6 +166,64 @@ static int iproc_rng200_init(struct hwrn
|
||||
@@ -158,6 +167,64 @@ static int iproc_rng200_init(struct hwrn
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -130,7 +138,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
static void iproc_rng200_cleanup(struct hwrng *rng)
|
||||
{
|
||||
struct iproc_rng200_dev *priv = to_rng_priv(rng);
|
||||
@@ -184,11 +250,17 @@ static int iproc_rng200_probe(struct pla
|
||||
@@ -184,11 +251,17 @@ static int iproc_rng200_probe(struct pla
|
||||
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
@ -0,0 +1,39 @@
|
||||
From 6f634d7efb8876e5953c30c0a613aaa5f575fe05 Mon Sep 17 00:00:00 2001
|
||||
From: Jim Quinlan <jim2101024@gmail.com>
|
||||
Date: Tue, 11 Oct 2022 14:42:07 -0400
|
||||
Subject: [PATCH] PCI: brcmstb: Wait for 100ms following PERST# deassert
|
||||
|
||||
commit 3ae140ad827b359bc4fa7c7985691c4c1e3ca8f4 upstream.
|
||||
|
||||
Be prudent and give some time for power and clocks to become stable. As
|
||||
described in the PCIe CEM specification sections 2.2 and 2.2.1; as well as
|
||||
PCIe r5.0, 6.6.1.
|
||||
|
||||
Link: https://lore.kernel.org/r/20221011184211.18128-3-jim2101024@gmail.com
|
||||
Signed-off-by: Jim Quinlan <jim2101024@gmail.com>
|
||||
Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
|
||||
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
---
|
||||
drivers/pci/controller/pcie-brcmstb.c | 11 +++++++++--
|
||||
1 file changed, 9 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pcie-brcmstb.c
|
||||
+++ b/drivers/pci/controller/pcie-brcmstb.c
|
||||
@@ -1038,8 +1038,15 @@ static int brcm_pcie_start_link(struct b
|
||||
pcie->perst_set(pcie, 0);
|
||||
|
||||
/*
|
||||
- * Give the RC/EP time to wake up, before trying to configure RC.
|
||||
- * Intermittently check status for link-up, up to a total of 100ms.
|
||||
+ * Wait for 100ms after PERST# deassertion; see PCIe CEM specification
|
||||
+ * sections 2.2, PCIe r5.0, 6.6.1.
|
||||
+ */
|
||||
+ msleep(100);
|
||||
+
|
||||
+ /*
|
||||
+ * Give the RC/EP even more time to wake up, before trying to
|
||||
+ * configure RC. Intermittently check status for link-up, up to a
|
||||
+ * total of 100ms.
|
||||
*/
|
||||
for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5)
|
||||
msleep(5);
|
@ -0,0 +1,47 @@
|
||||
From cc08810f89e52337a99cc6ae5f53f08588357c5f Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 19 Sep 2023 20:31:34 +0100
|
||||
Subject: [PATCH] overlays: Add a sample hat_map
|
||||
|
||||
The HAT map is way of associating named overlays with HATs whose
|
||||
EEPROMs were programmed with the contents of the overlay.
|
||||
Unfortunately, change in the DT and kernel drivers has meant that some
|
||||
of these embedded overlays no longer function, or even don't apply.
|
||||
|
||||
The HAT map is a mapping from HAT UUIDs to overlay names. If a HAT with
|
||||
a listed UUID is detected, the embedded overlay is ignored and the
|
||||
overlay named in the mapping is loaded in its place.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/Makefile | 2 +-
|
||||
arch/arm/boot/dts/overlays/hat_map.dts | 13 +++++++++++++
|
||||
2 files changed, 14 insertions(+), 1 deletion(-)
|
||||
create mode 100644 arch/arm/boot/dts/overlays/hat_map.dts
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/Makefile
|
||||
+++ b/arch/arm/boot/dts/overlays/Makefile
|
||||
@@ -1,6 +1,6 @@
|
||||
# Overlays for the Raspberry Pi platform
|
||||
|
||||
-dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb
|
||||
+dtb-$(CONFIG_ARCH_BCM2835) += overlay_map.dtb hat_map.dtb
|
||||
|
||||
dtbo-$(CONFIG_ARCH_BCM2835) += \
|
||||
act-led.dtbo \
|
||||
--- /dev/null
|
||||
+++ b/arch/arm/boot/dts/overlays/hat_map.dts
|
||||
@@ -0,0 +1,13 @@
|
||||
+/dts-v1/;
|
||||
+
|
||||
+/ {
|
||||
+ iqaudio-pi-codecplus {
|
||||
+ uuid = [ dc1c9594 c1ab 4c6c acda a88dc59a3c5b ];
|
||||
+ overlay = "iqaudio-codec";
|
||||
+ };
|
||||
+
|
||||
+ recalbox-rgbdual {
|
||||
+ uuid = [ 1c955808 681f 4bbc a2ef b7ea47cd388e ];
|
||||
+ overlay = "recalboxrgbdual";
|
||||
+ };
|
||||
+};
|
@ -0,0 +1,26 @@
|
||||
From 406e7dc82be6ce1b81c88b418640daeef6c2be42 Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Mon, 23 May 2022 16:56:44 +0100
|
||||
Subject: [PATCH] Revert "usb: phy: generic: Get the vbus supply"
|
||||
|
||||
This reverts commit c0ea202fbc855d60bc4a0603ca52a9e80654b327.
|
||||
---
|
||||
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
|
||||
@@ -265,13 +265,6 @@ int usb_phy_gen_create_phy(struct device
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
- 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";
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,282 @@
|
||||
From fa18902ee1e53ad391a455a01be3ab2ea1c5af5f Mon Sep 17 00:00:00 2001
|
||||
From: Dom Cobley <popcornmix@gmail.com>
|
||||
Date: Fri, 21 May 2021 12:33:38 +0100
|
||||
Subject: [PATCH] gpio_brcmstb: Allow to build for ARCH_BCM2835
|
||||
|
||||
gpio-brcmstb: Report the correct bank width
|
||||
|
||||
gpio: brcmstb: Use bank address as gpiochip label
|
||||
|
||||
If the path to the device node is used as gpiochip label then
|
||||
gpio-brcmstb instances with multiple banks end up with duplicated
|
||||
names. Instead, use a combination of the driver name with the physical
|
||||
address of the bank, which is both unique and helpful for devmem
|
||||
debugging.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
gpio: mmio: Add DIRECT mode for shared access
|
||||
|
||||
The generic MMIO GPIO library uses shadow registers for efficiency,
|
||||
but this breaks attempts by raspi-gpio to change other GPIOs in the
|
||||
same bank. Add a DIRECT mode that makes fewer assumptions about the
|
||||
existing register contents, but note that genuinely simultaneous
|
||||
accesses are likely to lose updates.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
gpio: brcmstb: Don't always clear interrupt mask
|
||||
|
||||
If the GPIO controller is not being used as an interrupt source
|
||||
leave the interrupt mask register alone. On BCM2712 it might be used
|
||||
to generate interrupts to the VPU firmware, and on other devices it
|
||||
doesn't matter since no interrupts will be generated.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/gpio/Kconfig | 2 +-
|
||||
drivers/gpio/gpio-brcmstb.c | 14 ++--
|
||||
drivers/gpio/gpio-mmio.c | 124 ++++++++++++++++++++++++++++++++++--
|
||||
include/linux/gpio/driver.h | 1 +
|
||||
4 files changed, 131 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/gpio/Kconfig
|
||||
+++ b/drivers/gpio/Kconfig
|
||||
@@ -203,7 +203,7 @@ config GPIO_BCM_VIRT
|
||||
config GPIO_BRCMSTB
|
||||
tristate "BRCMSTB GPIO support"
|
||||
default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
|
||||
- depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST)
|
||||
+ depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM2835 || COMPILE_TEST)
|
||||
select GPIO_GENERIC
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
--- a/drivers/gpio/gpio-brcmstb.c
|
||||
+++ b/drivers/gpio/gpio-brcmstb.c
|
||||
@@ -640,6 +640,8 @@ static int brcmstb_gpio_probe(struct pla
|
||||
#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
|
||||
flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
|
||||
#endif
|
||||
+ if (of_property_read_bool(np, "brcm,gpio-direct"))
|
||||
+ flags |= BGPIOF_REG_DIRECT;
|
||||
|
||||
of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
|
||||
bank_width) {
|
||||
@@ -689,7 +691,9 @@ static int brcmstb_gpio_probe(struct pla
|
||||
}
|
||||
|
||||
gc->owner = THIS_MODULE;
|
||||
- gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
|
||||
+ gc->label = devm_kasprintf(dev, GFP_KERNEL, "gpio-brcmstb@%zx",
|
||||
+ (size_t)res->start +
|
||||
+ GIO_BANK_OFF(bank->id, 0));
|
||||
if (!gc->label) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -698,7 +702,7 @@ static int brcmstb_gpio_probe(struct pla
|
||||
gc->of_gpio_n_cells = 2;
|
||||
gc->of_xlate = brcmstb_gpio_of_xlate;
|
||||
/* not all ngpio lines are valid, will use bank width later */
|
||||
- gc->ngpio = MAX_GPIO_PER_BANK;
|
||||
+ gc->ngpio = bank_width;
|
||||
gc->offset = bank->id * MAX_GPIO_PER_BANK;
|
||||
if (priv->parent_irq > 0)
|
||||
gc->to_irq = brcmstb_gpio_to_irq;
|
||||
@@ -707,8 +711,10 @@ static int brcmstb_gpio_probe(struct pla
|
||||
* Mask all interrupts by default, since wakeup interrupts may
|
||||
* be retained from S5 cold boot
|
||||
*/
|
||||
- need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
|
||||
- gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
|
||||
+ if (priv->parent_irq > 0) {
|
||||
+ need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
|
||||
+ gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
|
||||
+ }
|
||||
|
||||
err = gpiochip_add_data(gc, bank);
|
||||
if (err) {
|
||||
--- a/drivers/gpio/gpio-mmio.c
|
||||
+++ b/drivers/gpio/gpio-mmio.c
|
||||
@@ -232,6 +232,25 @@ static void bgpio_set(struct gpio_chip *
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
||||
+static void bgpio_set_direct(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
+{
|
||||
+ unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
+
|
||||
+ gc->bgpio_data = gc->read_reg(gc->reg_dat);
|
||||
+
|
||||
+ if (val)
|
||||
+ gc->bgpio_data |= mask;
|
||||
+ else
|
||||
+ gc->bgpio_data &= ~mask;
|
||||
+
|
||||
+ gc->write_reg(gc->reg_dat, gc->bgpio_data);
|
||||
+
|
||||
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
+}
|
||||
+
|
||||
static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
@@ -324,6 +343,27 @@ static void bgpio_set_multiple_with_clea
|
||||
gc->write_reg(gc->reg_clr, clear_mask);
|
||||
}
|
||||
|
||||
+static void bgpio_set_multiple_direct(struct gpio_chip *gc,
|
||||
+ unsigned long *mask,
|
||||
+ unsigned long *bits)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ unsigned long set_mask, clear_mask;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
+
|
||||
+ bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||
+
|
||||
+ gc->bgpio_data = gc->read_reg(gc->reg_dat);
|
||||
+
|
||||
+ gc->bgpio_data |= set_mask;
|
||||
+ gc->bgpio_data &= ~clear_mask;
|
||||
+
|
||||
+ gc->write_reg(gc->reg_dat, gc->bgpio_data);
|
||||
+
|
||||
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
+}
|
||||
+
|
||||
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
return 0;
|
||||
@@ -361,6 +401,29 @@ static int bgpio_dir_in(struct gpio_chip
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int bgpio_dir_in_direct(struct gpio_chip *gc, unsigned int gpio)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
+
|
||||
+ if (gc->reg_dir_in)
|
||||
+ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in);
|
||||
+ if (gc->reg_dir_out)
|
||||
+ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out);
|
||||
+
|
||||
+ gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
|
||||
+
|
||||
+ if (gc->reg_dir_in)
|
||||
+ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
|
||||
+ if (gc->reg_dir_out)
|
||||
+ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
|
||||
+
|
||||
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
/* Return 0 if output, 1 if input */
|
||||
@@ -399,6 +462,28 @@ static void bgpio_dir_out(struct gpio_ch
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
||||
+static void bgpio_dir_out_direct(struct gpio_chip *gc, unsigned int gpio,
|
||||
+ int val)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
+
|
||||
+ if (gc->reg_dir_in)
|
||||
+ gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in);
|
||||
+ if (gc->reg_dir_out)
|
||||
+ gc->bgpio_dir = gc->read_reg(gc->reg_dir_out);
|
||||
+
|
||||
+ gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
|
||||
+
|
||||
+ if (gc->reg_dir_in)
|
||||
+ gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
|
||||
+ if (gc->reg_dir_out)
|
||||
+ gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
|
||||
+
|
||||
+ raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
+}
|
||||
+
|
||||
static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
@@ -415,6 +500,22 @@ static int bgpio_dir_out_val_first(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int bgpio_dir_out_dir_first_direct(struct gpio_chip *gc,
|
||||
+ unsigned int gpio, int val)
|
||||
+{
|
||||
+ bgpio_dir_out_direct(gc, gpio, val);
|
||||
+ gc->set(gc, gpio, val);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bgpio_dir_out_val_first_direct(struct gpio_chip *gc,
|
||||
+ unsigned int gpio, int val)
|
||||
+{
|
||||
+ gc->set(gc, gpio, val);
|
||||
+ bgpio_dir_out_direct(gc, gpio, val);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int bgpio_setup_accessors(struct device *dev,
|
||||
struct gpio_chip *gc,
|
||||
bool byte_be)
|
||||
@@ -508,6 +609,9 @@ static int bgpio_setup_io(struct gpio_ch
|
||||
} else if (flags & BGPIOF_NO_OUTPUT) {
|
||||
gc->set = bgpio_set_none;
|
||||
gc->set_multiple = NULL;
|
||||
+ } else if (flags & BGPIOF_REG_DIRECT) {
|
||||
+ gc->set = bgpio_set_direct;
|
||||
+ gc->set_multiple = bgpio_set_multiple_direct;
|
||||
} else {
|
||||
gc->set = bgpio_set;
|
||||
gc->set_multiple = bgpio_set_multiple;
|
||||
@@ -544,11 +648,21 @@ static int bgpio_setup_direction(struct
|
||||
if (dirout || dirin) {
|
||||
gc->reg_dir_out = dirout;
|
||||
gc->reg_dir_in = dirin;
|
||||
- if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||
- gc->direction_output = bgpio_dir_out_dir_first;
|
||||
- else
|
||||
- gc->direction_output = bgpio_dir_out_val_first;
|
||||
- gc->direction_input = bgpio_dir_in;
|
||||
+ if (flags & BGPIOF_REG_DIRECT) {
|
||||
+ if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||
+ gc->direction_output =
|
||||
+ bgpio_dir_out_dir_first_direct;
|
||||
+ else
|
||||
+ gc->direction_output =
|
||||
+ bgpio_dir_out_val_first_direct;
|
||||
+ gc->direction_input = bgpio_dir_in_direct;
|
||||
+ } else {
|
||||
+ if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||
+ gc->direction_output = bgpio_dir_out_dir_first;
|
||||
+ else
|
||||
+ gc->direction_output = bgpio_dir_out_val_first;
|
||||
+ gc->direction_input = bgpio_dir_in;
|
||||
+ }
|
||||
gc->get_direction = bgpio_get_dir;
|
||||
} else {
|
||||
if (flags & BGPIOF_NO_OUTPUT)
|
||||
--- a/include/linux/gpio/driver.h
|
||||
+++ b/include/linux/gpio/driver.h
|
||||
@@ -690,6 +690,7 @@ int bgpio_init(struct gpio_chip *gc, str
|
||||
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
|
||||
#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
|
||||
#define BGPIOF_NO_SET_ON_INPUT BIT(6)
|
||||
+#define BGPIOF_REG_DIRECT BIT(7) /* ignore shadow registers */
|
||||
|
||||
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq);
|
@ -0,0 +1,20 @@
|
||||
From 22ae3b2ee3293278e647877b269a5aebad3f077d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Thu, 27 May 2021 11:46:30 +0100
|
||||
Subject: [PATCH] Allow RESET_BRCMSTB on ARCH_BCM2835
|
||||
|
||||
---
|
||||
drivers/reset/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/reset/Kconfig
|
||||
+++ b/drivers/reset/Kconfig
|
||||
@@ -51,7 +51,7 @@ config RESET_BERLIN
|
||||
|
||||
config RESET_BRCMSTB
|
||||
tristate "Broadcom STB reset controller"
|
||||
- depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
+ depends on ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
|
||||
default ARCH_BRCMSTB
|
||||
help
|
||||
This enables the reset controller driver for Broadcom STB SoCs using
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,498 @@
|
||||
From b627647c4500d39cb026924b608841fdf4d4d7e9 Mon Sep 17 00:00:00 2001
|
||||
From: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
Date: Thu, 29 Oct 2020 09:57:16 +0800
|
||||
Subject: [PATCH] mmc: brcmstb: add support for BCM2712
|
||||
|
||||
BCM2712 has an SD Express capable SDHCI implementation and uses
|
||||
the SDIO CFG register block present on other STB chips.
|
||||
|
||||
Add plumbing for SD Express handover and BCM2712-specific functions.
|
||||
|
||||
Due to the common bus infrastructure between BCM2711 and BCM2712,
|
||||
the driver also needs to implement 32-bit IO accessors.
|
||||
|
||||
mmc: brcmstb: override card presence if broken-cd is set
|
||||
|
||||
Not just if the card is declared as nonremovable.
|
||||
|
||||
sdhci: brcmstb: align SD express switchover with SD spec v8.00
|
||||
|
||||
Part 1 of the Physical specification, figure 3-24, details the switch
|
||||
sequence for cards initially probed as SD. Add a missing check for DAT2
|
||||
level after switching VDD2 on.
|
||||
|
||||
sdhci: brcmstb: clean up SD Express probe and error handling
|
||||
|
||||
Refactor to avoid spurious error messages in dmesg if the requisite SD
|
||||
Express DT nodes aren't present.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
mmc: sdhci-brcmstb: only use the delay line PHY for tuneable speeds
|
||||
|
||||
The MMC core has a 200MHz core clock which allows the use of DDR50 and
|
||||
below without incremental phase tuning. SDR50/SDR104 and the EMMC HS200
|
||||
speeds require tuning.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
---
|
||||
drivers/mmc/host/Kconfig | 2 +
|
||||
drivers/mmc/host/sdhci-brcmstb.c | 356 +++++++++++++++++++++++++++++++
|
||||
2 files changed, 358 insertions(+)
|
||||
|
||||
--- a/drivers/mmc/host/Kconfig
|
||||
+++ b/drivers/mmc/host/Kconfig
|
||||
@@ -1082,7 +1082,9 @@ config MMC_SDHCI_BRCMSTB
|
||||
tristate "Broadcom SDIO/SD/MMC support"
|
||||
depends on ARCH_BRCMSTB || BMIPS_GENERIC
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
+ select MMC_SDHCI_IO_ACCESSORS
|
||||
select MMC_CQHCI
|
||||
+ select OF_DYNAMIC
|
||||
default y
|
||||
help
|
||||
This selects support for the SDIO/SD/MMC Host Controller on
|
||||
--- a/drivers/mmc/host/sdhci-brcmstb.c
|
||||
+++ b/drivers/mmc/host/sdhci-brcmstb.c
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
+#include <linux/pinctrl/consumer.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
@@ -26,18 +28,43 @@
|
||||
|
||||
#define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0)
|
||||
#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1)
|
||||
+#define BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS BIT(2)
|
||||
|
||||
#define SDHCI_ARASAN_CQE_BASE_ADDR 0x200
|
||||
|
||||
+#define SDIO_CFG_CTRL 0x0
|
||||
+#define SDIO_CFG_CTRL_SDCD_N_TEST_EN BIT(31)
|
||||
+#define SDIO_CFG_CTRL_SDCD_N_TEST_LEV BIT(30)
|
||||
+
|
||||
+#define SDIO_CFG_SD_PIN_SEL 0x44
|
||||
+#define SDIO_CFG_SD_PIN_SEL_MASK 0x3
|
||||
+#define SDIO_CFG_SD_PIN_SEL_CARD BIT(1)
|
||||
+
|
||||
+#define SDIO_CFG_MAX_50MHZ_MODE 0x1ac
|
||||
+#define SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE BIT(31)
|
||||
+#define SDIO_CFG_MAX_50MHZ_MODE_ENABLE BIT(0)
|
||||
+
|
||||
struct sdhci_brcmstb_priv {
|
||||
void __iomem *cfg_regs;
|
||||
unsigned int flags;
|
||||
struct clk *base_clk;
|
||||
u32 base_freq_hz;
|
||||
+ u32 shadow_cmd;
|
||||
+ u32 shadow_blk;
|
||||
+ bool is_cmd_shadowed;
|
||||
+ bool is_blk_shadowed;
|
||||
+ struct regulator *sde_1v8;
|
||||
+ struct device_node *sde_pcie;
|
||||
+ void *__iomem sde_ioaddr;
|
||||
+ void *__iomem sde_ioaddr2;
|
||||
+ struct pinctrl *pinctrl;
|
||||
+ struct pinctrl_state *pins_default;
|
||||
+ struct pinctrl_state *pins_sdex;
|
||||
};
|
||||
|
||||
struct brcmstb_match_priv {
|
||||
void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios);
|
||||
+ void (*cfginit)(struct sdhci_host *host);
|
||||
struct sdhci_ops *ops;
|
||||
const unsigned int flags;
|
||||
};
|
||||
@@ -94,6 +121,124 @@ static void sdhci_brcmstb_set_clock(stru
|
||||
sdhci_enable_clk(host, clk);
|
||||
}
|
||||
|
||||
+#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
|
||||
+
|
||||
+static inline u32 sdhci_brcmstb_32only_readl(struct sdhci_host *host, int reg)
|
||||
+{
|
||||
+ u32 val = readl(host->ioaddr + reg);
|
||||
+
|
||||
+ pr_debug("%s: readl [0x%02x] 0x%08x\n",
|
||||
+ mmc_hostname(host->mmc), reg, val);
|
||||
+ return val;
|
||||
+}
|
||||
+
|
||||
+static u16 sdhci_brcmstb_32only_readw(struct sdhci_host *host, int reg)
|
||||
+{
|
||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
+ u32 val;
|
||||
+ u16 word;
|
||||
+
|
||||
+ if ((reg == SDHCI_TRANSFER_MODE) && brcmstb_priv->is_cmd_shadowed) {
|
||||
+ /* Get the saved transfer mode */
|
||||
+ val = brcmstb_priv->shadow_cmd;
|
||||
+ } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
|
||||
+ brcmstb_priv->is_blk_shadowed) {
|
||||
+ /* Get the saved block info */
|
||||
+ val = brcmstb_priv->shadow_blk;
|
||||
+ } else {
|
||||
+ val = sdhci_brcmstb_32only_readl(host, (reg & ~3));
|
||||
+ }
|
||||
+ word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
|
||||
+ return word;
|
||||
+}
|
||||
+
|
||||
+static u8 sdhci_brcmstb_32only_readb(struct sdhci_host *host, int reg)
|
||||
+{
|
||||
+ u32 val = sdhci_brcmstb_32only_readl(host, (reg & ~3));
|
||||
+ u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff;
|
||||
+ return byte;
|
||||
+}
|
||||
+
|
||||
+static inline void sdhci_brcmstb_32only_writel(struct sdhci_host *host, u32 val, int reg)
|
||||
+{
|
||||
+ pr_debug("%s: writel [0x%02x] 0x%08x\n",
|
||||
+ mmc_hostname(host->mmc), reg, val);
|
||||
+
|
||||
+ writel(val, host->ioaddr + reg);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * BCM2712 unfortunately carries with it a perennial bug with the SD controller
|
||||
+ * register interface present on previous chips (2711/2709/2708). Accesses must
|
||||
+ * be dword-sized and a read-modify-write cycle to the 32-bit registers
|
||||
+ * containing the COMMAND, TRANSFER_MODE, BLOCK_SIZE and BLOCK_COUNT registers
|
||||
+ * tramples the upper/lower 16 bits of data written. BCM2712 does not seem to
|
||||
+ * need the extreme delay between each write as on previous chips, just the
|
||||
+ * serialisation of writes to these registers in a single 32-bit operation.
|
||||
+ */
|
||||
+static void sdhci_brcmstb_32only_writew(struct sdhci_host *host, u16 val, int reg)
|
||||
+{
|
||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
+ u32 word_shift = REG_OFFSET_IN_BITS(reg);
|
||||
+ u32 mask = 0xffff << word_shift;
|
||||
+ u32 oldval, newval;
|
||||
+
|
||||
+ if (reg == SDHCI_COMMAND) {
|
||||
+ /* Write the block now as we are issuing a command */
|
||||
+ if (brcmstb_priv->is_blk_shadowed) {
|
||||
+ sdhci_brcmstb_32only_writel(host, brcmstb_priv->shadow_blk,
|
||||
+ SDHCI_BLOCK_SIZE);
|
||||
+ brcmstb_priv->is_blk_shadowed = false;
|
||||
+ }
|
||||
+ oldval = brcmstb_priv->shadow_cmd;
|
||||
+ brcmstb_priv->is_cmd_shadowed = false;
|
||||
+ } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
|
||||
+ brcmstb_priv->is_blk_shadowed) {
|
||||
+ /* Block size and count are stored in shadow reg */
|
||||
+ oldval = brcmstb_priv->shadow_blk;
|
||||
+ } else {
|
||||
+ /* Read reg, all other registers are not shadowed */
|
||||
+ oldval = sdhci_brcmstb_32only_readl(host, (reg & ~3));
|
||||
+ }
|
||||
+ newval = (oldval & ~mask) | (val << word_shift);
|
||||
+
|
||||
+ if (reg == SDHCI_TRANSFER_MODE) {
|
||||
+ /* Save the transfer mode until the command is issued */
|
||||
+ brcmstb_priv->shadow_cmd = newval;
|
||||
+ brcmstb_priv->is_cmd_shadowed = true;
|
||||
+ } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
|
||||
+ /* Save the block info until the command is issued */
|
||||
+ brcmstb_priv->shadow_blk = newval;
|
||||
+ brcmstb_priv->is_blk_shadowed = true;
|
||||
+ } else {
|
||||
+ /* Command or other regular 32-bit write */
|
||||
+ sdhci_brcmstb_32only_writel(host, newval, reg & ~3);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void sdhci_brcmstb_32only_writeb(struct sdhci_host *host, u8 val, int reg)
|
||||
+{
|
||||
+ u32 oldval = sdhci_brcmstb_32only_readl(host, (reg & ~3));
|
||||
+ u32 byte_shift = REG_OFFSET_IN_BITS(reg);
|
||||
+ u32 mask = 0xff << byte_shift;
|
||||
+ u32 newval = (oldval & ~mask) | (val << byte_shift);
|
||||
+
|
||||
+ sdhci_brcmstb_32only_writel(host, newval, reg & ~3);
|
||||
+}
|
||||
+
|
||||
+static void sdhci_brcmstb_set_power(struct sdhci_host *host, unsigned char mode,
|
||||
+ unsigned short vdd)
|
||||
+{
|
||||
+ if (!IS_ERR(host->mmc->supply.vmmc)) {
|
||||
+ struct mmc_host *mmc = host->mmc;
|
||||
+
|
||||
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
|
||||
+ }
|
||||
+ sdhci_set_power_noreg(host, mode, vdd);
|
||||
+}
|
||||
+
|
||||
static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
|
||||
unsigned int timing)
|
||||
{
|
||||
@@ -123,6 +268,146 @@ static void sdhci_brcmstb_set_uhs_signal
|
||||
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||
}
|
||||
|
||||
+static void sdhci_brcmstb_cfginit_2712(struct sdhci_host *host)
|
||||
+{
|
||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
+ bool want_dll = false;
|
||||
+ u32 uhs_mask = (MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104);
|
||||
+ u32 hsemmc_mask = (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS200_1_2V_SDR |
|
||||
+ MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V);
|
||||
+ u32 reg;
|
||||
+
|
||||
+ if (!(host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)) {
|
||||
+ if((host->mmc->caps & uhs_mask) || (host->mmc->caps2 & hsemmc_mask))
|
||||
+ want_dll = true;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If we want a speed that requires tuning,
|
||||
+ * then select the delay line PHY as the clock source.
|
||||
+ */
|
||||
+ if (want_dll) {
|
||||
+ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
|
||||
+ reg &= ~SDIO_CFG_MAX_50MHZ_MODE_ENABLE;
|
||||
+ reg |= SDIO_CFG_MAX_50MHZ_MODE_STRAP_OVERRIDE;
|
||||
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_MAX_50MHZ_MODE);
|
||||
+ }
|
||||
+
|
||||
+ if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) ||
|
||||
+ (host->mmc->caps & MMC_CAP_NEEDS_POLL)) {
|
||||
+ /* Force presence */
|
||||
+ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_CTRL);
|
||||
+ reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV;
|
||||
+ reg |= SDIO_CFG_CTRL_SDCD_N_TEST_EN;
|
||||
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_CTRL);
|
||||
+ } else {
|
||||
+ /* Enable card detection line */
|
||||
+ reg = readl(brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL);
|
||||
+ reg &= ~SDIO_CFG_SD_PIN_SEL_MASK;
|
||||
+ reg |= SDIO_CFG_SD_PIN_SEL_CARD;
|
||||
+ writel(reg, brcmstb_priv->cfg_regs + SDIO_CFG_SD_PIN_SEL);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int bcm2712_init_sd_express(struct sdhci_host *host, struct mmc_ios *ios)
|
||||
+{
|
||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
+ struct sdhci_brcmstb_priv *brcmstb_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
+ struct device *dev = host->mmc->parent;
|
||||
+ u32 ctrl_val;
|
||||
+ u32 present_state;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!brcmstb_priv->sde_ioaddr || !brcmstb_priv->sde_ioaddr2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!brcmstb_priv->pinctrl)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* Turn off the SD clock first */
|
||||
+ sdhci_set_clock(host, 0);
|
||||
+
|
||||
+ /* Disable SD DAT0-3 pulls */
|
||||
+ pinctrl_select_state(brcmstb_priv->pinctrl, brcmstb_priv->pins_sdex);
|
||||
+
|
||||
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr);
|
||||
+ dev_dbg(dev, "ctrl_val 1 %08x\n", ctrl_val);
|
||||
+
|
||||
+ /* Tri-state the SD pins */
|
||||
+ ctrl_val |= 0x1ff8;
|
||||
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr);
|
||||
+ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr));
|
||||
+ /* Let voltages settle */
|
||||
+ udelay(100);
|
||||
+
|
||||
+ /* Enable the PCIe sideband pins */
|
||||
+ ctrl_val &= ~0x6000;
|
||||
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr);
|
||||
+ dev_dbg(dev, "ctrl_val 1->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr));
|
||||
+ /* Let voltages settle */
|
||||
+ udelay(100);
|
||||
+
|
||||
+ /* Turn on the 1v8 VDD2 regulator */
|
||||
+ ret = regulator_enable(brcmstb_priv->sde_1v8);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Wait for Tpvcrl */
|
||||
+ msleep(1);
|
||||
+
|
||||
+ /* Sample DAT2 (CLKREQ#) - if low, card is in PCIe mode */
|
||||
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
|
||||
+ present_state = (present_state & SDHCI_DATA_LVL_MASK) >> SDHCI_DATA_LVL_SHIFT;
|
||||
+ dev_dbg(dev, "state = 0x%08x\n", present_state);
|
||||
+
|
||||
+ if (present_state & BIT(2)) {
|
||||
+ dev_err(dev, "DAT2 still high, abandoning SDex switch\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* Turn on the LCPLL PTEST mux */
|
||||
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr2 + 20); // misc5
|
||||
+ ctrl_val &= ~(0x7 << 7);
|
||||
+ ctrl_val |= 3 << 7;
|
||||
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr2 + 20);
|
||||
+ dev_dbg(dev, "misc 5->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2 + 20));
|
||||
+
|
||||
+ /* PTEST diff driver enable */
|
||||
+ ctrl_val = readl(brcmstb_priv->sde_ioaddr2);
|
||||
+ ctrl_val |= BIT(21);
|
||||
+ writel(ctrl_val, brcmstb_priv->sde_ioaddr2);
|
||||
+
|
||||
+ dev_dbg(dev, "misc 0->%08x (%08x)\n", ctrl_val, readl(brcmstb_priv->sde_ioaddr2));
|
||||
+
|
||||
+ /* Wait for more than the minimum Tpvpgl time */
|
||||
+ msleep(100);
|
||||
+
|
||||
+ if (brcmstb_priv->sde_pcie) {
|
||||
+ struct of_changeset changeset;
|
||||
+ static struct property okay_property = {
|
||||
+ .name = "status",
|
||||
+ .value = "okay",
|
||||
+ .length = 5,
|
||||
+ };
|
||||
+
|
||||
+ /* Enable the pcie controller */
|
||||
+ of_changeset_init(&changeset);
|
||||
+ ret = of_changeset_update_property(&changeset,
|
||||
+ brcmstb_priv->sde_pcie,
|
||||
+ &okay_property);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "%s: failed to update property - %d\n", __func__,
|
||||
+ ret);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ ret = of_changeset_apply(&changeset);
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(dev, "%s -> %d\n", __func__, ret);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
|
||||
{
|
||||
sdhci_dumpregs(mmc_priv(mmc));
|
||||
@@ -155,6 +440,21 @@ static struct sdhci_ops sdhci_brcmstb_op
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
};
|
||||
|
||||
+static struct sdhci_ops sdhci_brcmstb_ops_2712 = {
|
||||
+ .read_l = sdhci_brcmstb_32only_readl,
|
||||
+ .read_w = sdhci_brcmstb_32only_readw,
|
||||
+ .read_b = sdhci_brcmstb_32only_readb,
|
||||
+ .write_l = sdhci_brcmstb_32only_writel,
|
||||
+ .write_w = sdhci_brcmstb_32only_writew,
|
||||
+ .write_b = sdhci_brcmstb_32only_writeb,
|
||||
+ .set_clock = sdhci_set_clock,
|
||||
+ .set_power = sdhci_brcmstb_set_power,
|
||||
+ .set_bus_width = sdhci_set_bus_width,
|
||||
+ .reset = sdhci_reset,
|
||||
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
+ .init_sd_express = bcm2712_init_sd_express,
|
||||
+};
|
||||
+
|
||||
static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
|
||||
.set_clock = sdhci_brcmstb_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
@@ -179,10 +479,16 @@ static const struct brcmstb_match_priv m
|
||||
.ops = &sdhci_brcmstb_ops_7216,
|
||||
};
|
||||
|
||||
+static const struct brcmstb_match_priv match_priv_2712 = {
|
||||
+ .cfginit = sdhci_brcmstb_cfginit_2712,
|
||||
+ .ops = &sdhci_brcmstb_ops_2712,
|
||||
+};
|
||||
+
|
||||
static const struct of_device_id sdhci_brcm_of_match[] = {
|
||||
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
|
||||
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
|
||||
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
|
||||
+ { .compatible = "brcm,bcm2712-sdhci", .data = &match_priv_2712 },
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -256,6 +562,7 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
u32 actual_clock_mhz;
|
||||
struct sdhci_host *host;
|
||||
struct resource *iomem;
|
||||
+ bool no_pinctrl = false;
|
||||
struct clk *clk;
|
||||
struct clk *base_clk = NULL;
|
||||
int res;
|
||||
@@ -290,6 +597,11 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
|
||||
}
|
||||
|
||||
+ priv->sde_pcie = of_parse_phandle(pdev->dev.of_node,
|
||||
+ "sde-pcie", 0);
|
||||
+ if (priv->sde_pcie)
|
||||
+ priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
|
||||
+
|
||||
/* Map in the non-standard CFG registers */
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
priv->cfg_regs = devm_ioremap_resource(&pdev->dev, iomem);
|
||||
@@ -303,6 +615,43 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
+ priv->sde_1v8 = devm_regulator_get_optional(&pdev->dev, "sde-1v8");
|
||||
+ if (IS_ERR(priv->sde_1v8))
|
||||
+ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
|
||||
+
|
||||
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
+ if (iomem) {
|
||||
+ priv->sde_ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
|
||||
+ if (IS_ERR(priv->sde_ioaddr))
|
||||
+ priv->sde_ioaddr = NULL;
|
||||
+ }
|
||||
+
|
||||
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 3);
|
||||
+ if (iomem) {
|
||||
+ priv->sde_ioaddr2 = devm_ioremap_resource(&pdev->dev, iomem);
|
||||
+ if (IS_ERR(priv->sde_ioaddr2))
|
||||
+ priv->sde_ioaddr = NULL;
|
||||
+ }
|
||||
+
|
||||
+ priv->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
+ if (IS_ERR(priv->pinctrl)) {
|
||||
+ no_pinctrl = true;
|
||||
+ }
|
||||
+ priv->pins_default = pinctrl_lookup_state(priv->pinctrl, "default");
|
||||
+ if (IS_ERR(priv->pins_default)) {
|
||||
+ dev_dbg(&pdev->dev, "No pinctrl default state\n");
|
||||
+ no_pinctrl = true;
|
||||
+ }
|
||||
+ priv->pins_sdex = pinctrl_lookup_state(priv->pinctrl, "sd-express");
|
||||
+ if (IS_ERR(priv->pins_sdex)) {
|
||||
+ dev_dbg(&pdev->dev, "No pinctrl sd-express state\n");
|
||||
+ no_pinctrl = true;
|
||||
+ }
|
||||
+ if (no_pinctrl || !priv->sde_ioaddr || !priv->sde_ioaddr2) {
|
||||
+ priv->pinctrl = NULL;
|
||||
+ priv->flags &= ~BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Automatic clock gating does not work for SD cards that may
|
||||
* voltage switch so only enable it for non-removable devices.
|
||||
@@ -319,6 +668,13 @@ static int sdhci_brcmstb_probe(struct pl
|
||||
(host->mmc->caps2 & MMC_CAP2_HS400_ES))
|
||||
host->mmc_host_ops.hs400_enhanced_strobe = match_priv->hs400es;
|
||||
|
||||
+ if (host->ops->init_sd_express &&
|
||||
+ (priv->flags & BRCMSTB_PRIV_FLAGS_HAS_SD_EXPRESS))
|
||||
+ host->mmc->caps2 |= MMC_CAP2_SD_EXP;
|
||||
+
|
||||
+ if(match_priv->cfginit)
|
||||
+ match_priv->cfginit(host);
|
||||
+
|
||||
/*
|
||||
* Supply the existing CAPS, but clear the UHS modes. This
|
||||
* will allow these modes to be specified by device tree
|
@ -0,0 +1,90 @@
|
||||
From 9564939f1a92e5f9807461539de28c50e5bee440 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 6 Jul 2021 09:45:36 +0100
|
||||
Subject: [PATCH] sdhci: Add SD Express hook
|
||||
|
||||
sdhci: remove PYA0_INTR_BUG quirk. Add quirks to disable some of the higher SDR speeds at 1.8v.
|
||||
---
|
||||
drivers/mmc/host/sdhci-of-dwcmshc.c | 5 ++++-
|
||||
drivers/mmc/host/sdhci.c | 19 +++++++++++++++++++
|
||||
drivers/mmc/host/sdhci.h | 6 ++++++
|
||||
3 files changed, 29 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
@@ -363,7 +363,10 @@ static const struct sdhci_pltfm_data sdh
|
||||
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
- SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
+ SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
|
||||
+ SDHCI_QUIRK2_NO_SDR50 |
|
||||
+ SDHCI_QUIRK2_NO_SDR104 |
|
||||
+ SDHCI_QUIRK2_NO_SDR25,
|
||||
};
|
||||
|
||||
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
--- a/drivers/mmc/host/sdhci.c
|
||||
+++ b/drivers/mmc/host/sdhci.c
|
||||
@@ -3071,6 +3071,15 @@ static void sdhci_card_event(struct mmc_
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
+static int sdhci_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
+{
|
||||
+ struct sdhci_host *host = mmc_priv(mmc);
|
||||
+
|
||||
+ if (!host->ops->init_sd_express)
|
||||
+ return -EOPNOTSUPP;
|
||||
+ return host->ops->init_sd_express(host, ios);
|
||||
+}
|
||||
+
|
||||
static const struct mmc_host_ops sdhci_ops = {
|
||||
.request = sdhci_request,
|
||||
.post_req = sdhci_post_req,
|
||||
@@ -3086,6 +3095,7 @@ static const struct mmc_host_ops sdhci_o
|
||||
.execute_tuning = sdhci_execute_tuning,
|
||||
.card_event = sdhci_card_event,
|
||||
.card_busy = sdhci_card_busy,
|
||||
+ .init_sd_express = sdhci_init_sd_express,
|
||||
};
|
||||
|
||||
/*****************************************************************************\
|
||||
@@ -4605,6 +4615,15 @@ int sdhci_setup_host(struct sdhci_host *
|
||||
!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
|
||||
mmc->caps |= MMC_CAP_UHS_DDR50;
|
||||
|
||||
+ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR25)
|
||||
+ mmc->caps &= ~MMC_CAP_UHS_SDR25;
|
||||
+
|
||||
+ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR50)
|
||||
+ mmc->caps &= ~MMC_CAP_UHS_SDR50;
|
||||
+
|
||||
+ if (host->quirks2 & SDHCI_QUIRK2_NO_SDR104)
|
||||
+ mmc->caps &= ~MMC_CAP_UHS_SDR104;
|
||||
+
|
||||
/* Does the host need tuning for SDR50? */
|
||||
if (host->caps1 & SDHCI_USE_SDR50_TUNING)
|
||||
host->flags |= SDHCI_SDR50_NEEDS_TUNING;
|
||||
--- a/drivers/mmc/host/sdhci.h
|
||||
+++ b/drivers/mmc/host/sdhci.h
|
||||
@@ -481,6 +481,11 @@ struct sdhci_host {
|
||||
/* Issue CMD and DATA reset together */
|
||||
#define SDHCI_QUIRK2_ISSUE_CMD_DAT_RESET_TOGETHER (1<<19)
|
||||
|
||||
+/* Quirks to ignore a speed if a that speed is unreliable */
|
||||
+#define SDHCI_QUIRK2_NO_SDR25 (1<<19)
|
||||
+#define SDHCI_QUIRK2_NO_SDR50 (1<<20)
|
||||
+#define SDHCI_QUIRK2_NO_SDR104 (1<<21)
|
||||
+
|
||||
int irq; /* Device IRQ */
|
||||
void __iomem *ioaddr; /* Mapped address */
|
||||
phys_addr_t mapbase; /* physical address base */
|
||||
@@ -663,6 +668,7 @@ struct sdhci_ops {
|
||||
void (*request_done)(struct sdhci_host *host,
|
||||
struct mmc_request *mrq);
|
||||
void (*dump_vendor_regs)(struct sdhci_host *host);
|
||||
+ int (*init_sd_express)(struct sdhci_host *host, struct mmc_ios *ios);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,386 @@
|
||||
From 89b748416358e4e04765b9a4f20e1c3d256b9d9e Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 28 Jul 2021 11:13:39 +0100
|
||||
Subject: [PATCH] irqchip: irq-bcm2712-mip: Support for 2712's MIP
|
||||
|
||||
irqchip: irq-bcm2712-mip: specify bitmap search size as ilog2(N) not N
|
||||
|
||||
Freeing also has the same interface.
|
||||
|
||||
irqchip: irq-bcm2712-mip: Fix build warnings
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
irqchip: bcm2712-mip: add a quick hack to optionally shift MSI vectors
|
||||
|
||||
There are two MIP peripherals in bcm2712, the first gets a first-class
|
||||
treatment where 64 consecutive GIC SPIs are assigned to all 64 output
|
||||
vectors. The second gets an agglomeration of 17 GIC SPIs, but only 8 of
|
||||
these are consecutive starting at the 8th output vector.
|
||||
|
||||
For now, allow the use of this smaller contiguous range within a larger
|
||||
whole.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
---
|
||||
drivers/irqchip/Kconfig | 8 +
|
||||
drivers/irqchip/Makefile | 1 +
|
||||
drivers/irqchip/irq-bcm2712-mip.c | 325 ++++++++++++++++++++++++++++++
|
||||
3 files changed, 334 insertions(+)
|
||||
create mode 100644 drivers/irqchip/irq-bcm2712-mip.c
|
||||
|
||||
--- a/drivers/irqchip/Kconfig
|
||||
+++ b/drivers/irqchip/Kconfig
|
||||
@@ -109,6 +109,14 @@ config I8259
|
||||
bool
|
||||
select IRQ_DOMAIN
|
||||
|
||||
+config BCM2712_MIP
|
||||
+ bool "Broadcom 2712 MSI-X Interrupt Peripheral support"
|
||||
+ depends on ARM_GIC
|
||||
+ select GENERIC_IRQ_CHIP
|
||||
+ select IRQ_DOMAIN
|
||||
+ help
|
||||
+ Enable support for the Broadcom BCM2712 MSI-X target peripheral.
|
||||
+
|
||||
config BCM6345_L1_IRQ
|
||||
bool
|
||||
select GENERIC_IRQ_CHIP
|
||||
--- a/drivers/irqchip/Makefile
|
||||
+++ b/drivers/irqchip/Makefile
|
||||
@@ -63,6 +63,7 @@ obj-$(CONFIG_XTENSA_MX) += irq-xtensa-
|
||||
obj-$(CONFIG_XILINX_INTC) += irq-xilinx-intc.o
|
||||
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
|
||||
obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o
|
||||
+obj-$(CONFIG_BCM2712_MIP) += irq-bcm2712-mip.o
|
||||
obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o
|
||||
obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o
|
||||
obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/irqchip/irq-bcm2712-mip.c
|
||||
@@ -0,0 +1,325 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * Copyright (C) 2021 Raspberry Pi Ltd., All Rights Reserved.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/pci.h>
|
||||
+#include <linux/msi.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_irq.h>
|
||||
+#include <linux/of_pci.h>
|
||||
+
|
||||
+#include <linux/irqchip.h>
|
||||
+
|
||||
+#define MIP_INT_RAISED 0x00
|
||||
+#define MIP_INT_CLEARED 0x10
|
||||
+#define MIP_INT_CFGL_HOST 0x20
|
||||
+#define MIP_INT_CFGH_HOST 0x30
|
||||
+#define MIP_INT_MASKL_HOST 0x40
|
||||
+#define MIP_INT_MASKH_HOST 0x50
|
||||
+#define MIP_INT_MASKL_VPU 0x60
|
||||
+#define MIP_INT_MASKH_VPU 0x70
|
||||
+#define MIP_INT_STATUSL_HOST 0x80
|
||||
+#define MIP_INT_STATUSH_HOST 0x90
|
||||
+#define MIP_INT_STATUSL_VPU 0xa0
|
||||
+#define MIP_INT_STATUSH_VPU 0xb0
|
||||
+
|
||||
+struct mip_priv {
|
||||
+ spinlock_t msi_map_lock;
|
||||
+ spinlock_t hw_lock;
|
||||
+ void * __iomem base;
|
||||
+ phys_addr_t msg_addr;
|
||||
+ u32 msi_base; /* The SGI number that MSIs start */
|
||||
+ u32 num_msis; /* The number of SGIs for MSIs */
|
||||
+ u32 msi_offset; /* Shift the allocated msi up by N */
|
||||
+ unsigned long *msi_map;
|
||||
+};
|
||||
+
|
||||
+static void mip_mask_msi_irq(struct irq_data *d)
|
||||
+{
|
||||
+ pci_msi_mask_irq(d);
|
||||
+ irq_chip_mask_parent(d);
|
||||
+}
|
||||
+
|
||||
+static void mip_unmask_msi_irq(struct irq_data *d)
|
||||
+{
|
||||
+ pci_msi_unmask_irq(d);
|
||||
+ irq_chip_unmask_parent(d);
|
||||
+}
|
||||
+
|
||||
+static void mip_compose_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
+{
|
||||
+ struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
+
|
||||
+ msg->address_hi = upper_32_bits(priv->msg_addr);
|
||||
+ msg->address_lo = lower_32_bits(priv->msg_addr);
|
||||
+ msg->data = d->hwirq;
|
||||
+}
|
||||
+
|
||||
+// The "bus-specific" irq_chip (the MIP doesn't _have_ to be used with PCIe)
|
||||
+
|
||||
+static struct irq_chip mip_msi_irq_chip = {
|
||||
+ .name = "MIP-MSI",
|
||||
+ .irq_unmask = mip_unmask_msi_irq,
|
||||
+ .irq_mask = mip_mask_msi_irq,
|
||||
+ .irq_eoi = irq_chip_eoi_parent,
|
||||
+ .irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
+};
|
||||
+
|
||||
+static struct msi_domain_info mip_msi_domain_info = {
|
||||
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
+ MSI_FLAG_PCI_MSIX),
|
||||
+ .chip = &mip_msi_irq_chip,
|
||||
+};
|
||||
+
|
||||
+// The "middle" irq_chip (the hardware control part)
|
||||
+
|
||||
+static struct irq_chip mip_irq_chip = {
|
||||
+ .name = "MIP",
|
||||
+ .irq_mask = irq_chip_mask_parent,
|
||||
+ .irq_unmask = irq_chip_unmask_parent,
|
||||
+ .irq_eoi = irq_chip_eoi_parent,
|
||||
+ .irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
+ .irq_set_type = irq_chip_set_type_parent,
|
||||
+ .irq_compose_msi_msg = mip_compose_msi_msg,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+// And a domain to connect it to its parent (the GIC)
|
||||
+
|
||||
+static int mip_irq_domain_alloc(struct irq_domain *domain,
|
||||
+ unsigned int virq, unsigned int nr_irqs,
|
||||
+ void *args)
|
||||
+{
|
||||
+ struct mip_priv *priv = domain->host_data;
|
||||
+ struct irq_fwspec fwspec;
|
||||
+ struct irq_data *irqd;
|
||||
+ int hwirq, ret, i;
|
||||
+
|
||||
+ spin_lock(&priv->msi_map_lock);
|
||||
+
|
||||
+ hwirq = bitmap_find_free_region(priv->msi_map, priv->num_msis, ilog2(nr_irqs));
|
||||
+
|
||||
+ spin_unlock(&priv->msi_map_lock);
|
||||
+
|
||||
+ if (hwirq < 0)
|
||||
+ return -ENOSPC;
|
||||
+
|
||||
+ hwirq += priv->msi_offset;
|
||||
+ fwspec.fwnode = domain->parent->fwnode;
|
||||
+ fwspec.param_count = 3;
|
||||
+ fwspec.param[0] = 0;
|
||||
+ fwspec.param[1] = hwirq + priv->msi_base;
|
||||
+ fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
|
||||
+
|
||||
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &fwspec);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ for (i = 0; i < nr_irqs; i++) {
|
||||
+ irqd = irq_domain_get_irq_data(domain->parent, virq + i);
|
||||
+ irqd->chip->irq_set_type(irqd, IRQ_TYPE_EDGE_RISING);
|
||||
+
|
||||
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
|
||||
+ &mip_irq_chip, priv);
|
||||
+ irqd = irq_get_irq_data(virq + i);
|
||||
+ irqd_set_single_target(irqd);
|
||||
+ irqd_set_affinity_on_activate(irqd);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mip_irq_domain_free(struct irq_domain *domain,
|
||||
+ unsigned int virq, unsigned int nr_irqs)
|
||||
+{
|
||||
+ struct irq_data *d = irq_domain_get_irq_data(domain, virq);
|
||||
+ struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
+
|
||||
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
|
||||
+ d->hwirq -= priv->msi_offset;
|
||||
+
|
||||
+ spin_lock(&priv->msi_map_lock);
|
||||
+
|
||||
+ bitmap_release_region(priv->msi_map, d->hwirq, ilog2(nr_irqs));
|
||||
+
|
||||
+ spin_unlock(&priv->msi_map_lock);
|
||||
+}
|
||||
+
|
||||
+#if 0
|
||||
+static int mip_irq_domain_activate(struct irq_domain *domain,
|
||||
+ struct irq_data *d, bool reserve)
|
||||
+{
|
||||
+ struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
+ unsigned long flags;
|
||||
+ unsigned int irq = d->hwirq;
|
||||
+ void *__iomem reg = priv->base +
|
||||
+ ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST);
|
||||
+ u32 val;
|
||||
+
|
||||
+ spin_lock_irqsave(&priv->hw_lock, flags);
|
||||
+ val = readl(reg);
|
||||
+ val &= ~(1 << (irq % 32)); // Clear the mask
|
||||
+ writel(val, reg);
|
||||
+ spin_unlock_irqrestore(&priv->hw_lock, flags);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mip_irq_domain_deactivate(struct irq_domain *domain,
|
||||
+ struct irq_data *d)
|
||||
+{
|
||||
+ struct mip_priv *priv = irq_data_get_irq_chip_data(d);
|
||||
+ unsigned long flags;
|
||||
+ unsigned int irq = d->hwirq - priv->msi_base;
|
||||
+ void *__iomem reg = priv->base +
|
||||
+ ((irq < 32) ? MIP_INT_MASKL_HOST : MIP_INT_MASKH_HOST);
|
||||
+ u32 val;
|
||||
+
|
||||
+ spin_lock_irqsave(&priv->hw_lock, flags);
|
||||
+ val = readl(reg);
|
||||
+ val |= (1 << (irq % 32)); // Mask it out
|
||||
+ writel(val, reg);
|
||||
+ spin_unlock_irqrestore(&priv->hw_lock, flags);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static const struct irq_domain_ops mip_irq_domain_ops = {
|
||||
+ .alloc = mip_irq_domain_alloc,
|
||||
+ .free = mip_irq_domain_free,
|
||||
+ //.activate = mip_irq_domain_activate,
|
||||
+ //.deactivate = mip_irq_domain_deactivate,
|
||||
+};
|
||||
+
|
||||
+static int mip_init_domains(struct mip_priv *priv,
|
||||
+ struct device_node *node)
|
||||
+{
|
||||
+ struct irq_domain *middle_domain, *msi_domain, *gic_domain;
|
||||
+ struct device_node *gic_node;
|
||||
+
|
||||
+ gic_node = of_irq_find_parent(node);
|
||||
+ if (!gic_node) {
|
||||
+ pr_err("Failed to find the GIC node\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ gic_domain = irq_find_host(gic_node);
|
||||
+ if (!gic_domain) {
|
||||
+ pr_err("Failed to find the GIC domain\n");
|
||||
+ return -ENXIO;
|
||||
+ }
|
||||
+
|
||||
+ middle_domain = irq_domain_add_tree(NULL,
|
||||
+ &mip_irq_domain_ops,
|
||||
+ priv);
|
||||
+ if (!middle_domain) {
|
||||
+ pr_err("Failed to create the MIP middle domain\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ middle_domain->parent = gic_domain;
|
||||
+
|
||||
+ msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(node),
|
||||
+ &mip_msi_domain_info,
|
||||
+ middle_domain);
|
||||
+ if (!msi_domain) {
|
||||
+ pr_err("Failed to create MSI domain\n");
|
||||
+ irq_domain_remove(middle_domain);
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __init mip_of_msi_init(struct device_node *node,
|
||||
+ struct device_node *parent)
|
||||
+{
|
||||
+ struct mip_priv *priv;
|
||||
+ struct resource res;
|
||||
+ int ret;
|
||||
+
|
||||
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ spin_lock_init(&priv->msi_map_lock);
|
||||
+ spin_lock_init(&priv->hw_lock);
|
||||
+
|
||||
+ ret = of_address_to_resource(node, 0, &res);
|
||||
+ if (ret) {
|
||||
+ pr_err("Failed to allocate resource\n");
|
||||
+ goto err_priv;
|
||||
+ }
|
||||
+
|
||||
+ if (of_property_read_u32(node, "brcm,msi-base-spi", &priv->msi_base)) {
|
||||
+ pr_err("Unable to parse MSI base\n");
|
||||
+ ret = -EINVAL;
|
||||
+ goto err_priv;
|
||||
+ }
|
||||
+
|
||||
+ if (of_property_read_u32(node, "brcm,msi-num-spis", &priv->num_msis)) {
|
||||
+ pr_err("Unable to parse MSI numbers\n");
|
||||
+ ret = -EINVAL;
|
||||
+ goto err_priv;
|
||||
+ }
|
||||
+
|
||||
+ if (of_property_read_u32(node, "brcm,msi-offset", &priv->msi_offset))
|
||||
+ priv->msi_offset = 0;
|
||||
+
|
||||
+ if (of_property_read_u64(node, "brcm,msi-pci-addr", &priv->msg_addr)) {
|
||||
+ pr_err("Unable to parse MSI address\n");
|
||||
+ ret = -EINVAL;
|
||||
+ goto err_priv;
|
||||
+ }
|
||||
+
|
||||
+ priv->base = ioremap(res.start, resource_size(&res));
|
||||
+ if (!priv->base) {
|
||||
+ pr_err("Failed to ioremap regs\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_priv;
|
||||
+ }
|
||||
+
|
||||
+ priv->msi_map = kcalloc(BITS_TO_LONGS(priv->num_msis),
|
||||
+ sizeof(*priv->msi_map),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!priv->msi_map) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_base;
|
||||
+ }
|
||||
+
|
||||
+ pr_debug("Registering %d msixs, starting at %d\n",
|
||||
+ priv->num_msis, priv->msi_base);
|
||||
+
|
||||
+ /*
|
||||
+ * Begin with all MSI-Xs masked in for the host, masked out for the
|
||||
+ * VPU, and edge-triggered.
|
||||
+ */
|
||||
+ writel(0, priv->base + MIP_INT_MASKL_HOST);
|
||||
+ writel(0, priv->base + MIP_INT_MASKH_HOST);
|
||||
+ writel(~0, priv->base + MIP_INT_MASKL_VPU);
|
||||
+ writel(~0, priv->base + MIP_INT_MASKH_VPU);
|
||||
+ writel(~0, priv->base + MIP_INT_CFGL_HOST);
|
||||
+ writel(~0, priv->base + MIP_INT_CFGH_HOST);
|
||||
+
|
||||
+ ret = mip_init_domains(priv, node);
|
||||
+ if (ret) {
|
||||
+ pr_err("Failed to allocate msi_map\n");
|
||||
+ goto err_map;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_map:
|
||||
+ kfree(priv->msi_map);
|
||||
+
|
||||
+err_base:
|
||||
+ iounmap(priv->base);
|
||||
+
|
||||
+err_priv:
|
||||
+ kfree(priv);
|
||||
+
|
||||
+ pr_err("%s: failed - err %d\n", __func__, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+IRQCHIP_DECLARE(bcm_mip, "brcm,bcm2712-mip-intc", mip_of_msi_init);
|
@ -0,0 +1,47 @@
|
||||
From 87b1126181f79fb2558652af0d7fafd9deaab5f3 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 7 Sep 2021 14:49:00 +0100
|
||||
Subject: [PATCH] reset: reset-brcmstb-rescal: Support shared use
|
||||
|
||||
reset_control_reset should not be used with shared reset controllers.
|
||||
Add support for reset_control_assert and _deassert to get the desired
|
||||
behaviour and avoid ugly warnings in the kernel log.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/reset/reset-brcmstb-rescal.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/reset/reset-brcmstb-rescal.c
|
||||
+++ b/drivers/reset/reset-brcmstb-rescal.c
|
||||
@@ -20,6 +20,7 @@ struct brcm_rescal_reset {
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
+/* Also doubles a deassert */
|
||||
static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
@@ -52,6 +53,13 @@ static int brcm_rescal_reset_set(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* A dummy function - deassert/reset does all the work */
|
||||
+static int brcm_rescal_reset_assert(struct reset_controller_dev *rcdev,
|
||||
+ unsigned long id)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev,
|
||||
const struct of_phandle_args *reset_spec)
|
||||
{
|
||||
@@ -61,6 +69,8 @@ static int brcm_rescal_reset_xlate(struc
|
||||
|
||||
static const struct reset_control_ops brcm_rescal_reset_ops = {
|
||||
.reset = brcm_rescal_reset_set,
|
||||
+ .deassert = brcm_rescal_reset_set,
|
||||
+ .assert = brcm_rescal_reset_assert,
|
||||
};
|
||||
|
||||
static int brcm_rescal_reset_probe(struct platform_device *pdev)
|
@ -0,0 +1,418 @@
|
||||
From bd36586dd9e05bde8e23dc3d99771269b48b65f8 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 10 Sep 2021 17:20:45 +0100
|
||||
Subject: [PATCH] net: macb: Also set DMA coherent mask
|
||||
|
||||
macb: Add device tree properties that allow configuration of the AXI max pipeline register
|
||||
|
||||
net: macb: add support for ethtool interrupt moderation configuration
|
||||
|
||||
Only global throttling of rx or tx by time quanta is supported.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
macb: add platform device shutdown function. Prevents AXI master over PCIE from hanging when the host is rebooted.
|
||||
|
||||
net: macb: increase polling interval for MDIO completion
|
||||
|
||||
MDIO is a slow bus (single-digit MHz). Polling at 1us intervals
|
||||
is a bit aggressive, so increase to 100us as the transaction
|
||||
usually takes 100-200us to complete.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
net: macb: Several patches for RP1
|
||||
|
||||
64-bit RX fix
|
||||
|
||||
Also set DMA coherent mask
|
||||
|
||||
Add device tree properties that allow configuration of the AXI max
|
||||
pipeline register
|
||||
|
||||
Add support for ethtool interrupt moderation configuration
|
||||
|
||||
Only global throttling of rx or tx by time quanta is supported.
|
||||
|
||||
Add platform device shutdown function. Prevents AXI master over PCIE
|
||||
from hanging when the host is rebooted.
|
||||
|
||||
Increase polling interval for MDIO completion
|
||||
|
||||
MDIO is a slow bus (single-digit MHz). Polling at 1us intervals
|
||||
is a bit aggressive, so increase to 100us as the transaction
|
||||
usually takes 100-200us to complete.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
net: macb: Support the phy-reset-gpios property
|
||||
|
||||
Allow a PHY to be reset with an optional GPIO. The reset duration can
|
||||
be specified in milliseconds - the default is 10ms.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
|
||||
drivers: net: macb: close device on driver shutdown
|
||||
|
||||
Fix some suspicious locking and instead call into macb_close, which
|
||||
deregisters and frees all resources the corresponding macb_open
|
||||
claimed.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
net: macb: add hack to prevent TX stalls in a quiet system
|
||||
|
||||
See https://github.com/raspberrypi/linux-2712/issues/89
|
||||
|
||||
There is some critical window during TX where a further write to the
|
||||
TSTART bit while TX is active does not cause newly queued TX descriptors
|
||||
to be consumed.
|
||||
|
||||
For now "wait a bit, then try anyway" seems to work.
|
||||
|
||||
Requires further investigation, but this unsticks NFS reliably.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
net: macb: set default interrupt moderation for GEM hardware
|
||||
|
||||
Defaulting to intmod = 0 is antisocial, as the MAC can generate over
|
||||
130,000 interrupts per second. 50us is a sensible default.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
---
|
||||
drivers/net/ethernet/cadence/macb.h | 25 ++++
|
||||
drivers/net/ethernet/cadence/macb_main.c | 151 ++++++++++++++++++++++-
|
||||
2 files changed, 174 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/ethernet/cadence/macb.h
|
||||
+++ b/drivers/net/ethernet/cadence/macb.h
|
||||
@@ -84,6 +84,8 @@
|
||||
#define GEM_DMACFG 0x0010 /* DMA Configuration */
|
||||
#define GEM_JML 0x0048 /* Jumbo Max Length */
|
||||
#define GEM_HS_MAC_CONFIG 0x0050 /* GEM high speed config */
|
||||
+#define GEM_AMP 0x0054 /* AXI Max Pipeline */
|
||||
+#define GEM_INTMOD 0x005c /* Interrupt moderation */
|
||||
#define GEM_HRB 0x0080 /* Hash Bottom */
|
||||
#define GEM_HRT 0x0084 /* Hash Top */
|
||||
#define GEM_SA1B 0x0088 /* Specific1 Bottom */
|
||||
@@ -346,6 +348,21 @@
|
||||
#define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */
|
||||
#define GEM_ADDR64_SIZE 1
|
||||
|
||||
+/* Bitfields in AMP */
|
||||
+#define GEM_AR2R_MAX_PIPE_OFFSET 0 /* Maximum number of outstanding AXI read requests */
|
||||
+#define GEM_AR2R_MAX_PIPE_SIZE 8
|
||||
+#define GEM_AW2W_MAX_PIPE_OFFSET 8 /* Maximum number of outstanding AXI write requests */
|
||||
+#define GEM_AW2W_MAX_PIPE_SIZE 8
|
||||
+#define GEM_AW2B_FILL_OFFSET 16 /* Select wether the max AW2W transactions operates between: */
|
||||
+#define GEM_AW2B_FILL_AW2W 0 /* 0: the AW to W AXI channel */
|
||||
+#define GEM_AW2B_FILL_AW2B 1 /* 1: AW to B channel */
|
||||
+#define GEM_AW2B_FILL_SIZE 1
|
||||
+
|
||||
+/* Bitfields in INTMOD */
|
||||
+#define GEM_RX_MODERATION_OFFSET 0 /* RX interrupt moderation */
|
||||
+#define GEM_RX_MODERATION_SIZE 8
|
||||
+#define GEM_TX_MODERATION_OFFSET 16 /* TX interrupt moderation */
|
||||
+#define GEM_TX_MODERATION_SIZE 8
|
||||
|
||||
/* Bitfields in NSR */
|
||||
#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */
|
||||
@@ -798,6 +815,7 @@
|
||||
})
|
||||
|
||||
#define MACB_READ_NSR(bp) macb_readl(bp, NSR)
|
||||
+#define MACB_READ_TSR(bp) macb_readl(bp, TSR)
|
||||
|
||||
/* struct macb_dma_desc - Hardware DMA descriptor
|
||||
* @addr: DMA address of data buffer
|
||||
@@ -1217,6 +1235,7 @@ struct macb_queue {
|
||||
dma_addr_t tx_ring_dma;
|
||||
struct work_struct tx_error_task;
|
||||
bool txubr_pending;
|
||||
+ bool tx_pending;
|
||||
struct napi_struct napi_tx;
|
||||
|
||||
dma_addr_t rx_ring_dma;
|
||||
@@ -1286,9 +1305,15 @@ struct macb {
|
||||
|
||||
u32 caps;
|
||||
unsigned int dma_burst_length;
|
||||
+ u8 aw2w_max_pipe;
|
||||
+ u8 ar2r_max_pipe;
|
||||
+ bool use_aw2b_fill;
|
||||
|
||||
phy_interface_t phy_interface;
|
||||
|
||||
+ struct gpio_desc *phy_reset_gpio;
|
||||
+ int phy_reset_ms;
|
||||
+
|
||||
/* AT91RM9200 transmit queue (1 on wire + 1 queued) */
|
||||
struct macb_tx_skb rm9200_txq[2];
|
||||
unsigned int max_tx_length;
|
||||
--- a/drivers/net/ethernet/cadence/macb_main.c
|
||||
+++ b/drivers/net/ethernet/cadence/macb_main.c
|
||||
@@ -41,6 +41,9 @@
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include "macb.h"
|
||||
|
||||
+static unsigned int txdelay = 35;
|
||||
+module_param(txdelay, uint, 0644);
|
||||
+
|
||||
/* This structure is only used for MACB on SiFive FU540 devices */
|
||||
struct sifive_fu540_macb_mgmt {
|
||||
void __iomem *reg;
|
||||
@@ -336,7 +339,7 @@ static int macb_mdio_wait_for_idle(struc
|
||||
u32 val;
|
||||
|
||||
return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE),
|
||||
- 1, MACB_MDIO_TIMEOUT);
|
||||
+ 100, MACB_MDIO_TIMEOUT);
|
||||
}
|
||||
|
||||
static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
@@ -442,6 +445,19 @@ mdio_pm_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
+static int macb_mdio_reset(struct mii_bus *bus)
|
||||
+{
|
||||
+ struct macb *bp = bus->priv;
|
||||
+
|
||||
+ if (bp->phy_reset_gpio) {
|
||||
+ gpiod_set_value_cansleep(bp->phy_reset_gpio, 1);
|
||||
+ msleep(bp->phy_reset_ms);
|
||||
+ gpiod_set_value_cansleep(bp->phy_reset_gpio, 0);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void macb_init_buffers(struct macb *bp)
|
||||
{
|
||||
struct macb_queue *queue;
|
||||
@@ -915,6 +931,7 @@ static int macb_mii_init(struct macb *bp
|
||||
bp->mii_bus->name = "MACB_mii_bus";
|
||||
bp->mii_bus->read = &macb_mdio_read;
|
||||
bp->mii_bus->write = &macb_mdio_write;
|
||||
+ bp->mii_bus->reset = &macb_mdio_reset;
|
||||
snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
|
||||
bp->pdev->name, bp->pdev->id);
|
||||
bp->mii_bus->priv = bp;
|
||||
@@ -1584,6 +1601,11 @@ static int macb_rx(struct macb_queue *qu
|
||||
|
||||
macb_init_rx_ring(queue);
|
||||
queue_writel(queue, RBQP, queue->rx_ring_dma);
|
||||
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
|
||||
+ if (bp->hw_dma_cap & HW_DMA_CAP_64B)
|
||||
+ macb_writel(bp, RBQPH,
|
||||
+ upper_32_bits(queue->rx_ring_dma));
|
||||
+#endif
|
||||
|
||||
macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
|
||||
|
||||
@@ -1884,8 +1906,9 @@ static irqreturn_t macb_interrupt(int ir
|
||||
queue_writel(queue, ISR, MACB_BIT(TCOMP) |
|
||||
MACB_BIT(TXUBR));
|
||||
|
||||
- if (status & MACB_BIT(TXUBR)) {
|
||||
+ if (status & MACB_BIT(TXUBR) || queue->tx_pending) {
|
||||
queue->txubr_pending = true;
|
||||
+ queue->tx_pending = 0;
|
||||
wmb(); // ensure softirq can see update
|
||||
}
|
||||
|
||||
@@ -2332,6 +2355,11 @@ static netdev_tx_t macb_start_xmit(struc
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
spin_lock_irq(&bp->lock);
|
||||
+
|
||||
+ /* TSTART write might get dropped, so make the IRQ retrigger a buffer read */
|
||||
+ if (macb_readl(bp, TSR) & MACB_BIT(TGO))
|
||||
+ queue->tx_pending = 1;
|
||||
+
|
||||
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
|
||||
spin_unlock_irq(&bp->lock);
|
||||
|
||||
@@ -2699,6 +2727,37 @@ static void macb_configure_dma(struct ma
|
||||
}
|
||||
}
|
||||
|
||||
+static void gem_init_axi(struct macb *bp)
|
||||
+{
|
||||
+ u32 amp;
|
||||
+
|
||||
+ /* AXI pipeline setup - don't touch values unless specified in device
|
||||
+ * tree. Some hardware could have reset values > 1.
|
||||
+ */
|
||||
+ amp = gem_readl(bp, AMP);
|
||||
+
|
||||
+ if (bp->use_aw2b_fill)
|
||||
+ amp = GEM_BFINS(AW2B_FILL, bp->use_aw2b_fill, amp);
|
||||
+ if (bp->aw2w_max_pipe)
|
||||
+ amp = GEM_BFINS(AW2W_MAX_PIPE, bp->aw2w_max_pipe, amp);
|
||||
+ if (bp->ar2r_max_pipe)
|
||||
+ amp = GEM_BFINS(AR2R_MAX_PIPE, bp->ar2r_max_pipe, amp);
|
||||
+
|
||||
+ gem_writel(bp, AMP, amp);
|
||||
+}
|
||||
+
|
||||
+static void gem_init_intmod(struct macb *bp)
|
||||
+{
|
||||
+ unsigned int throttle;
|
||||
+ u32 intmod = 0;
|
||||
+
|
||||
+ /* Use sensible interrupt moderation thresholds (50us rx and tx) */
|
||||
+ throttle = (1000 * 50) / 800;
|
||||
+ intmod = GEM_BFINS(TX_MODERATION, throttle, intmod);
|
||||
+ intmod = GEM_BFINS(RX_MODERATION, throttle, intmod);
|
||||
+ gem_writel(bp, INTMOD, intmod);
|
||||
+}
|
||||
+
|
||||
static void macb_init_hw(struct macb *bp)
|
||||
{
|
||||
u32 config;
|
||||
@@ -2727,6 +2786,11 @@ static void macb_init_hw(struct macb *bp
|
||||
if (bp->caps & MACB_CAPS_JUMBO)
|
||||
bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
|
||||
|
||||
+ if (macb_is_gem(bp)) {
|
||||
+ gem_init_axi(bp);
|
||||
+ gem_init_intmod(bp);
|
||||
+ }
|
||||
+
|
||||
macb_configure_dma(bp);
|
||||
}
|
||||
|
||||
@@ -3072,6 +3136,52 @@ static void gem_get_ethtool_strings(stru
|
||||
}
|
||||
}
|
||||
|
||||
+static int gem_set_coalesce(struct net_device *dev,
|
||||
+ struct ethtool_coalesce *ec,
|
||||
+ struct kernel_ethtool_coalesce *kernel_coal,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct macb *bp = netdev_priv(dev);
|
||||
+ unsigned int tx_throttle;
|
||||
+ unsigned int rx_throttle;
|
||||
+ u32 intmod = 0;
|
||||
+
|
||||
+ /* GEM has simple IRQ throttling support. RX and TX interrupts
|
||||
+ * are separately moderated on 800ns quantums, with no support
|
||||
+ * for frame coalescing.
|
||||
+ */
|
||||
+
|
||||
+ /* Max is 255 * 0.8us = 204us. Zero implies no moderation. */
|
||||
+ if (ec->rx_coalesce_usecs > 204 || ec->tx_coalesce_usecs > 204)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ tx_throttle = (1000 * ec->tx_coalesce_usecs) / 800;
|
||||
+ rx_throttle = (1000 * ec->rx_coalesce_usecs) / 800;
|
||||
+
|
||||
+ intmod = GEM_BFINS(TX_MODERATION, tx_throttle, intmod);
|
||||
+ intmod = GEM_BFINS(RX_MODERATION, rx_throttle, intmod);
|
||||
+
|
||||
+ gem_writel(bp, INTMOD, intmod);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gem_get_coalesce(struct net_device *dev,
|
||||
+ struct ethtool_coalesce *ec,
|
||||
+ struct kernel_ethtool_coalesce *kernel_coal,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct macb *bp = netdev_priv(dev);
|
||||
+ u32 intmod;
|
||||
+
|
||||
+ intmod = gem_readl(bp, INTMOD);
|
||||
+
|
||||
+ ec->tx_coalesce_usecs = (GEM_BFEXT(TX_MODERATION, intmod) * 800) / 1000;
|
||||
+ ec->rx_coalesce_usecs = (GEM_BFEXT(RX_MODERATION, intmod) * 800) / 1000;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static struct net_device_stats *macb_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct macb *bp = netdev_priv(dev);
|
||||
@@ -3664,6 +3774,8 @@ static const struct ethtool_ops macb_eth
|
||||
};
|
||||
|
||||
static const struct ethtool_ops gem_ethtool_ops = {
|
||||
+ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
|
||||
+ ETHTOOL_COALESCE_TX_USECS,
|
||||
.get_regs_len = macb_get_regs_len,
|
||||
.get_regs = macb_get_regs,
|
||||
.get_wol = macb_get_wol,
|
||||
@@ -3673,6 +3785,8 @@ static const struct ethtool_ops gem_etht
|
||||
.get_ethtool_stats = gem_get_ethtool_stats,
|
||||
.get_strings = gem_get_ethtool_strings,
|
||||
.get_sset_count = gem_get_sset_count,
|
||||
+ .get_coalesce = gem_get_coalesce,
|
||||
+ .set_coalesce = gem_set_coalesce,
|
||||
.get_link_ksettings = macb_get_link_ksettings,
|
||||
.set_link_ksettings = macb_set_link_ksettings,
|
||||
.get_ringparam = macb_get_ringparam,
|
||||
@@ -4940,6 +5054,10 @@ static int macb_probe(struct platform_de
|
||||
|
||||
bp->usrio = macb_config->usrio;
|
||||
|
||||
+ device_property_read_u8(&pdev->dev, "cdns,aw2w-max-pipe", &bp->aw2w_max_pipe);
|
||||
+ device_property_read_u8(&pdev->dev, "cdns,ar2r-max-pipe", &bp->ar2r_max_pipe);
|
||||
+ bp->use_aw2b_fill = device_property_read_bool(&pdev->dev, "cdns,use-aw2b-fill");
|
||||
+
|
||||
spin_lock_init(&bp->lock);
|
||||
|
||||
/* setup capabilities */
|
||||
@@ -4995,6 +5113,21 @@ static int macb_probe(struct platform_de
|
||||
else
|
||||
bp->phy_interface = interface;
|
||||
|
||||
+ /* optional PHY reset-related properties */
|
||||
+ bp->phy_reset_gpio = devm_gpiod_get_optional(&pdev->dev, "phy-reset",
|
||||
+ GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(bp->phy_reset_gpio)) {
|
||||
+ dev_err(&pdev->dev, "Failed to obtain phy-reset gpio\n");
|
||||
+ err = PTR_ERR(bp->phy_reset_gpio);
|
||||
+ goto err_out_free_netdev;
|
||||
+ }
|
||||
+
|
||||
+ bp->phy_reset_ms = 10;
|
||||
+ of_property_read_u32(np, "phy-reset-duration", &bp->phy_reset_ms);
|
||||
+ /* A sane reset duration should not be longer than 1s */
|
||||
+ if (bp->phy_reset_ms > 1000)
|
||||
+ bp->phy_reset_ms = 1000;
|
||||
+
|
||||
/* IP specific init */
|
||||
err = init(pdev);
|
||||
if (err)
|
||||
@@ -5071,6 +5204,19 @@ static int macb_remove(struct platform_d
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void macb_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct net_device *dev;
|
||||
+
|
||||
+ dev = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ netif_device_detach(dev);
|
||||
+ if (netif_running(dev))
|
||||
+ dev_close(dev);
|
||||
+ rtnl_unlock();
|
||||
+}
|
||||
+
|
||||
static int __maybe_unused macb_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *netdev = dev_get_drvdata(dev);
|
||||
@@ -5285,6 +5431,7 @@ static const struct dev_pm_ops macb_pm_o
|
||||
static struct platform_driver macb_driver = {
|
||||
.probe = macb_probe,
|
||||
.remove = macb_remove,
|
||||
+ .shutdown = macb_shutdown,
|
||||
.driver = {
|
||||
.name = "macb",
|
||||
.of_match_table = of_match_ptr(macb_dt_ids),
|
@ -0,0 +1,384 @@
|
||||
From 4ffa5f2c5fc7854683964bb2f2bf23907c18213f Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
Date: Mon, 13 Sep 2021 11:14:32 +0100
|
||||
Subject: [PATCH] usb: dwc3: Set DMA and coherent masks early
|
||||
|
||||
dwc3 allocates scratch and event buffers in the top-level driver. Hack the
|
||||
probe function to set the DMA mask before trying to allocate these.
|
||||
|
||||
I think the event buffers are only used in device mode, but the scratch
|
||||
buffers may be used if core hibernation is enabled.
|
||||
|
||||
usb: dwc3: add support for new DT quirks
|
||||
|
||||
Apply the optional axi-pipe-limit and dis-in-autoretry-quirk properties
|
||||
during driver probe.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
phy: phy-brcm-usb: Add 2712 support
|
||||
|
||||
usb: dwc3: if the host controller instance number is present in DT, use it
|
||||
|
||||
If two instances of a dwc3 host controller are specified in devicetree,
|
||||
then the probe order may be arbitrary which results in the device names
|
||||
swapping on a per-boot basis.
|
||||
|
||||
If a "usb" alias with the instance number is specified, then use
|
||||
that to construct the device name instead of autogenerating one.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
rp1 dwc3 changes
|
||||
|
||||
drivers: usb: dwc3: allow setting GTXTHRCFG on dwc_usb3.0 hardware
|
||||
|
||||
Equivalent register fields exist in the SuperSpeed Host version of the
|
||||
hardware, so allow the use of TX thresholds if specified in devicetree.
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
|
||||
drivers: usb: dwc3: remove downstream quirk dis-in-autoretry
|
||||
|
||||
Upstream have unilaterally disabled the feature.
|
||||
|
||||
Partially reverts 6e9142a26ee0fdc3a5adc49ed6cedc0b16ec2ed1 (downstream)
|
||||
|
||||
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
---
|
||||
drivers/phy/broadcom/Kconfig | 2 +-
|
||||
.../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++
|
||||
drivers/phy/broadcom/phy-brcm-usb-init.h | 2 +
|
||||
drivers/phy/broadcom/phy-brcm-usb.c | 18 +++++-
|
||||
drivers/usb/dwc3/core.c | 52 ++++++++++++++++
|
||||
drivers/usb/dwc3/core.h | 10 ++++
|
||||
drivers/usb/dwc3/host.c | 17 ++++--
|
||||
7 files changed, 153 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/phy/broadcom/Kconfig
|
||||
+++ b/drivers/phy/broadcom/Kconfig
|
||||
@@ -93,7 +93,7 @@ config PHY_BRCM_SATA
|
||||
|
||||
config PHY_BRCM_USB
|
||||
tristate "Broadcom STB USB PHY driver"
|
||||
- depends on ARCH_BCMBCA || ARCH_BRCMSTB || COMPILE_TEST
|
||||
+ depends on ARCH_BCMBCA || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
|
||||
depends on OF
|
||||
select GENERIC_PHY
|
||||
select SOC_BRCMSTB if ARCH_BRCMSTB
|
||||
--- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
|
||||
+++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
|
||||
@@ -318,6 +318,36 @@ static void usb_init_common_7216(struct
|
||||
usb_init_common(params);
|
||||
}
|
||||
|
||||
+static void usb_init_common_2712(struct brcm_usb_init_params *params)
|
||||
+{
|
||||
+ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
+ void __iomem *bdc_ec = params->regs[BRCM_REGS_BDC_EC];
|
||||
+ u32 reg;
|
||||
+
|
||||
+ if (params->syscon_piarbctl)
|
||||
+ syscon_piarbctl_init(params->syscon_piarbctl);
|
||||
+
|
||||
+ USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
|
||||
+
|
||||
+ usb_wake_enable_7211b0(params, false);
|
||||
+
|
||||
+ usb_init_common(params);
|
||||
+
|
||||
+ /*
|
||||
+ * The BDC controller will get occasional failures with
|
||||
+ * the default "Read Transaction Size" of 6 (1024 bytes).
|
||||
+ * Set it to 4 (256 bytes).
|
||||
+ */
|
||||
+ if ((params->mode != USB_CTLR_MODE_HOST) && bdc_ec) {
|
||||
+ reg = brcm_usb_readl(bdc_ec + BDC_EC_AXIRDA);
|
||||
+ reg &= ~BDC_EC_AXIRDA_RTS_MASK;
|
||||
+ reg |= (0x4 << BDC_EC_AXIRDA_RTS_SHIFT);
|
||||
+ brcm_usb_writel(reg, bdc_ec + BDC_EC_AXIRDA);
|
||||
+ }
|
||||
+
|
||||
+ usb2_eye_fix_7211b0(params);
|
||||
+}
|
||||
+
|
||||
static void usb_init_xhci(struct brcm_usb_init_params *params)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
@@ -363,6 +393,18 @@ static void usb_uninit_common_7211b0(str
|
||||
|
||||
}
|
||||
|
||||
+static void usb_uninit_common_2712(struct brcm_usb_init_params *params)
|
||||
+{
|
||||
+ void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
+
|
||||
+ if (params->wake_enabled) {
|
||||
+ USB_CTRL_SET(ctrl, TEST_PORT_CTL, TPOUT_SEL_PME_GEN);
|
||||
+ usb_wake_enable_7211b0(params, true);
|
||||
+ } else {
|
||||
+ USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void usb_uninit_xhci(struct brcm_usb_init_params *params)
|
||||
{
|
||||
|
||||
@@ -417,6 +459,16 @@ static const struct brcm_usb_init_ops bc
|
||||
.set_dual_select = usb_set_dual_select,
|
||||
};
|
||||
|
||||
+static const struct brcm_usb_init_ops bcm2712_ops = {
|
||||
+ .init_ipp = usb_init_ipp,
|
||||
+ .init_common = usb_init_common_2712,
|
||||
+ .init_xhci = usb_init_xhci,
|
||||
+ .uninit_common = usb_uninit_common_2712,
|
||||
+ .uninit_xhci = usb_uninit_xhci,
|
||||
+ .get_dual_select = usb_get_dual_select,
|
||||
+ .set_dual_select = usb_set_dual_select,
|
||||
+};
|
||||
+
|
||||
void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
|
||||
{
|
||||
|
||||
@@ -434,3 +486,10 @@ void brcm_usb_dvr_init_7211b0(struct brc
|
||||
params->family_name = "7211";
|
||||
params->ops = &bcm7211b0_ops;
|
||||
}
|
||||
+
|
||||
+void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params)
|
||||
+{
|
||||
+ params->family_name = "2712";
|
||||
+ params->ops = &bcm2712_ops;
|
||||
+ params->suspend_with_clocks = true;
|
||||
+}
|
||||
--- a/drivers/phy/broadcom/phy-brcm-usb-init.h
|
||||
+++ b/drivers/phy/broadcom/phy-brcm-usb-init.h
|
||||
@@ -61,12 +61,14 @@ struct brcm_usb_init_params {
|
||||
const struct brcm_usb_init_ops *ops;
|
||||
struct regmap *syscon_piarbctl;
|
||||
bool wake_enabled;
|
||||
+ bool suspend_with_clocks;
|
||||
};
|
||||
|
||||
void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params);
|
||||
+void brcm_usb_dvr_init_2712(struct brcm_usb_init_params *params);
|
||||
|
||||
static inline u32 brcm_usb_readl(void __iomem *addr)
|
||||
{
|
||||
--- a/drivers/phy/broadcom/phy-brcm-usb.c
|
||||
+++ b/drivers/phy/broadcom/phy-brcm-usb.c
|
||||
@@ -76,7 +76,7 @@ struct brcm_usb_phy_data {
|
||||
};
|
||||
|
||||
static s8 *node_reg_names[BRCM_REGS_MAX] = {
|
||||
- "crtl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
|
||||
+ "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
|
||||
};
|
||||
|
||||
static int brcm_pm_notifier(struct notifier_block *notifier,
|
||||
@@ -315,6 +315,18 @@ static const struct match_chip_info chip
|
||||
.optional_reg = BRCM_REGS_BDC_EC,
|
||||
};
|
||||
|
||||
+static const struct match_chip_info chip_info_2712 = {
|
||||
+ .init_func = &brcm_usb_dvr_init_2712,
|
||||
+ .required_regs = {
|
||||
+ BRCM_REGS_CTRL,
|
||||
+ BRCM_REGS_XHCI_EC,
|
||||
+ BRCM_REGS_XHCI_GBL,
|
||||
+ BRCM_REGS_USB_MDIO,
|
||||
+ -1,
|
||||
+ },
|
||||
+ .optional_reg = BRCM_REGS_BDC_EC,
|
||||
+};
|
||||
+
|
||||
static const struct match_chip_info chip_info_7445 = {
|
||||
.init_func = &brcm_usb_dvr_init_7445,
|
||||
.required_regs = {
|
||||
@@ -338,6 +350,10 @@ static const struct of_device_id brcm_us
|
||||
.data = &chip_info_7211b0,
|
||||
},
|
||||
{
|
||||
+ .compatible = "brcm,bcm2712-usb-phy",
|
||||
+ .data = &chip_info_2712,
|
||||
+ },
|
||||
+ {
|
||||
.compatible = "brcm,brcmstb-usb-phy",
|
||||
.data = &chip_info_7445,
|
||||
},
|
||||
--- a/drivers/usb/dwc3/core.c
|
||||
+++ b/drivers/usb/dwc3/core.c
|
||||
@@ -1216,6 +1216,24 @@ static void dwc3_config_threshold(struct
|
||||
}
|
||||
}
|
||||
|
||||
+static void dwc3_set_axi_pipe_limit(struct dwc3 *dwc)
|
||||
+{
|
||||
+ struct device *dev = dwc->dev;
|
||||
+ u32 cfg;
|
||||
+
|
||||
+ if (!dwc->axi_pipe_limit)
|
||||
+ return;
|
||||
+ if (dwc->axi_pipe_limit > 16) {
|
||||
+ dev_err(dev, "Invalid axi_pipe_limit property\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1);
|
||||
+ cfg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT(15);
|
||||
+ cfg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(dwc->axi_pipe_limit - 1);
|
||||
+
|
||||
+ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, cfg);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* dwc3_core_init - Low-level initialization of DWC3 Core
|
||||
* @dwc: Pointer to our controller context structure
|
||||
@@ -1308,6 +1326,8 @@ static int dwc3_core_init(struct dwc3 *d
|
||||
|
||||
dwc3_set_incr_burst_type(dwc);
|
||||
|
||||
+ dwc3_set_axi_pipe_limit(dwc);
|
||||
+
|
||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||
ret = phy_power_on(dwc->usb2_generic_phy);
|
||||
@@ -1541,6 +1561,7 @@ static void dwc3_get_properties(struct d
|
||||
u8 tx_thr_num_pkt_prd = 0;
|
||||
u8 tx_max_burst_prd = 0;
|
||||
u8 tx_fifo_resize_max_num;
|
||||
+ u8 axi_pipe_limit;
|
||||
const char *usb_psy_name;
|
||||
int ret;
|
||||
|
||||
@@ -1563,6 +1584,9 @@ static void dwc3_get_properties(struct d
|
||||
*/
|
||||
tx_fifo_resize_max_num = 6;
|
||||
|
||||
+ /* Default to 0 (don't override hardware defaults) */
|
||||
+ axi_pipe_limit = 0;
|
||||
+
|
||||
dwc->maximum_speed = usb_get_maximum_speed(dev);
|
||||
dwc->max_ssp_rate = usb_get_maximum_ssp_rate(dev);
|
||||
dwc->dr_mode = usb_get_dr_mode(dev);
|
||||
@@ -1678,6 +1702,9 @@ static void dwc3_get_properties(struct d
|
||||
dwc->dis_split_quirk = device_property_read_bool(dev,
|
||||
"snps,dis-split-quirk");
|
||||
|
||||
+ device_property_read_u8(dev, "snps,axi-pipe-limit",
|
||||
+ &axi_pipe_limit);
|
||||
+
|
||||
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
|
||||
dwc->tx_de_emphasis = tx_de_emphasis;
|
||||
|
||||
@@ -1695,6 +1722,8 @@ static void dwc3_get_properties(struct d
|
||||
dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
|
||||
dwc->tx_max_burst_prd = tx_max_burst_prd;
|
||||
|
||||
+ dwc->axi_pipe_limit = axi_pipe_limit;
|
||||
+
|
||||
dwc->imod_interval = 0;
|
||||
|
||||
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
|
||||
@@ -1903,6 +1932,12 @@ static int dwc3_probe(struct platform_de
|
||||
|
||||
dwc3_get_properties(dwc);
|
||||
|
||||
+ if (!dwc->sysdev_is_parent) {
|
||||
+ ret = dma_set_mask_and_coherent(dwc->sysdev, DMA_BIT_MASK(64));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
dwc->reset = devm_reset_control_array_get_optional_shared(dev);
|
||||
if (IS_ERR(dwc->reset)) {
|
||||
ret = PTR_ERR(dwc->reset);
|
||||
--- a/drivers/usb/dwc3/core.h
|
||||
+++ b/drivers/usb/dwc3/core.h
|
||||
@@ -183,6 +183,9 @@
|
||||
#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
|
||||
#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff
|
||||
|
||||
+/* Global SoC Bus Configuration Register 1 */
|
||||
+#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) (((n) & 0xf) << 8)
|
||||
+
|
||||
/* Global Debug LSP MUX Select */
|
||||
#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */
|
||||
#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
|
||||
@@ -1056,6 +1059,7 @@ struct dwc3_scratchpad_array {
|
||||
* @tx_max_burst_prd: max periodic ESS transmit burst size
|
||||
* @tx_fifo_resize_max_num: max number of fifos allocated during txfifo resize
|
||||
* @clear_stall_protocol: endpoint number that requires a delayed status phase
|
||||
+ * @axi_max_pipe: set to override the maximum number of pipelined AXI transfers
|
||||
* @hsphy_interface: "utmi" or "ulpi"
|
||||
* @connected: true when we're connected to a host, false otherwise
|
||||
* @softconnect: true when gadget connect is called, false when disconnect runs
|
||||
@@ -1287,6 +1291,7 @@ struct dwc3 {
|
||||
u8 tx_max_burst_prd;
|
||||
u8 tx_fifo_resize_max_num;
|
||||
u8 clear_stall_protocol;
|
||||
+ u8 axi_pipe_limit;
|
||||
|
||||
const char *hsphy_interface;
|
||||
|
||||
--- a/drivers/usb/dwc3/host.c
|
||||
+++ b/drivers/usb/dwc3/host.c
|
||||
@@ -30,10 +30,10 @@ static void dwc3_host_fill_xhci_irq_res(
|
||||
|
||||
static int dwc3_host_get_irq(struct dwc3 *dwc)
|
||||
{
|
||||
- struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
|
||||
+ struct platform_device *pdev = to_platform_device(dwc->dev);
|
||||
int irq;
|
||||
|
||||
- irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
|
||||
+ irq = platform_get_irq_byname_optional(pdev, "host");
|
||||
if (irq > 0) {
|
||||
dwc3_host_fill_xhci_irq_res(dwc, irq, "host");
|
||||
goto out;
|
||||
@@ -42,7 +42,7 @@ static int dwc3_host_get_irq(struct dwc3
|
||||
if (irq == -EPROBE_DEFER)
|
||||
goto out;
|
||||
|
||||
- irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
|
||||
+ irq = platform_get_irq_byname_optional(pdev, "dwc_usb3");
|
||||
if (irq > 0) {
|
||||
dwc3_host_fill_xhci_irq_res(dwc, irq, "dwc_usb3");
|
||||
goto out;
|
||||
@@ -51,7 +51,7 @@ static int dwc3_host_get_irq(struct dwc3
|
||||
if (irq == -EPROBE_DEFER)
|
||||
goto out;
|
||||
|
||||
- irq = platform_get_irq(dwc3_pdev, 0);
|
||||
+ irq = platform_get_irq(pdev, 0);
|
||||
if (irq > 0) {
|
||||
dwc3_host_fill_xhci_irq_res(dwc, irq, NULL);
|
||||
goto out;
|
||||
@@ -66,16 +66,23 @@ out:
|
||||
|
||||
int dwc3_host_init(struct dwc3 *dwc)
|
||||
{
|
||||
+ struct platform_device *pdev = to_platform_device(dwc->dev);
|
||||
struct property_entry props[4];
|
||||
struct platform_device *xhci;
|
||||
int ret, irq;
|
||||
int prop_idx = 0;
|
||||
+ int id;
|
||||
|
||||
irq = dwc3_host_get_irq(dwc);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
- xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
|
||||
+ id = of_alias_get_id(pdev->dev.of_node, "usb");
|
||||
+ if (id >= 0)
|
||||
+ xhci = platform_device_alloc("xhci-hcd", id);
|
||||
+ else
|
||||
+ xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
|
||||
+
|
||||
if (!xhci) {
|
||||
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
|
||||
return -ENOMEM;
|
@ -0,0 +1,37 @@
|
||||
From 480c8e9f48f8a96c457eb3dc0079a73598fb7477 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.org>
|
||||
Date: Wed, 1 Dec 2021 19:43:08 +0000
|
||||
Subject: [PATCH] drm/panel/raspberrypi-touchscreen: Insert more delays.
|
||||
|
||||
This avoids failures in cases where the panel is enabled
|
||||
or re-probed very soon after being disabled or probed.
|
||||
These can occur because the Atmel device can mis-behave
|
||||
over I2C for a few ms after any write to the POWERON register.
|
||||
---
|
||||
drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
|
||||
+++ b/drivers/gpu/drm/panel/panel-raspberrypi-touchscreen.c
|
||||
@@ -299,6 +299,13 @@ static int rpi_touchscreen_prepare(struc
|
||||
struct rpi_touchscreen *ts = panel_to_ts(panel);
|
||||
int i, data;
|
||||
|
||||
+ /*
|
||||
+ * Power up the Toshiba bridge. The Atmel device can misbehave
|
||||
+ * over I2C for a few ms after writes to REG_POWERON (including the
|
||||
+ * write in rpi_touchscreen_disable()), so sleep before and after.
|
||||
+ * Also to ensure that the bridge has been off for at least 100ms.
|
||||
+ */
|
||||
+ msleep(100);
|
||||
rpi_touchscreen_i2c_write(ts, REG_POWERON, 1);
|
||||
usleep_range(20000, 25000);
|
||||
/* Wait for nPWRDWN to go low to indicate poweron is done. */
|
||||
@@ -431,6 +438,7 @@ static int rpi_touchscreen_probe(struct
|
||||
|
||||
/* Turn off at boot, so we can cleanly sequence powering on. */
|
||||
rpi_touchscreen_i2c_write(ts, REG_POWERON, 0);
|
||||
+ usleep_range(20000, 25000);
|
||||
|
||||
/* Look up the DSI host. It needs to probe before we do. */
|
||||
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,42 @@
|
||||
From 9a11300e46344917226b986a8740e7581d66adf3 Mon Sep 17 00:00:00 2001
|
||||
From: Naushir Patuck <naush@raspberrypi.com>
|
||||
Date: Mon, 7 Feb 2022 09:20:49 +0000
|
||||
Subject: [PATCH] V4L2: Add PiSP opaque formats to V4L2
|
||||
|
||||
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
---
|
||||
drivers/media/v4l2-core/v4l2-ioctl.c | 4 +++-
|
||||
include/uapi/linux/videodev2.h | 7 +++++++
|
||||
2 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
@@ -1452,7 +1452,9 @@ static void v4l_fill_fmtdesc(struct v4l2
|
||||
case V4L2_PIX_FMT_NV12M_10BE_8L128: descr = "10-bit NV12M (8x128 Linear, BE)"; break;
|
||||
case V4L2_META_FMT_SENSOR_DATA: descr = "Sensor Ancillary Metadata"; break;
|
||||
case V4L2_META_FMT_BCM2835_ISP_STATS: descr = "BCM2835 ISP Image Statistics"; break;
|
||||
- case V4L2_META_FMT_RPI_BE_CFG: descr = "PiSP Config format"; break;
|
||||
+ case V4L2_META_FMT_RPI_BE_CFG: descr = "PiSP BE Config format"; break;
|
||||
+ case V4L2_META_FMT_RPI_FE_CFG: descr = "PiSP FE Config format"; break;
|
||||
+ case V4L2_META_FMT_RPI_FE_STATS: descr = "PiSP FE Statistics format"; break;
|
||||
|
||||
default:
|
||||
/* Compressed formats */
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -826,8 +826,15 @@ struct v4l2_pix_format {
|
||||
#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */
|
||||
|
||||
/* The metadata format identifier for our configuration buffers. */
|
||||
+/* The metadata format identifier for BE configuration buffers. */
|
||||
#define V4L2_META_FMT_RPI_BE_CFG v4l2_fourcc('R', 'P', 'B', 'C')
|
||||
|
||||
+/* The metadata format identifier for FE configuration buffers. */
|
||||
+#define V4L2_META_FMT_RPI_FE_CFG v4l2_fourcc('R', 'P', 'F', 'C')
|
||||
+
|
||||
+/* The metadata format identifier for FE configuration buffers. */
|
||||
+#define V4L2_META_FMT_RPI_FE_STATS v4l2_fourcc('R', 'P', 'F', 'S')
|
||||
+
|
||||
/* priv field value to indicates that subsequent fields are valid. */
|
||||
#define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe
|
||||
|
@ -0,0 +1,39 @@
|
||||
From 01f31f4145d49a30eb553c65ea755dde8dba1de0 Mon Sep 17 00:00:00 2001
|
||||
From: Naushir Patuck <naush@raspberrypi.com>
|
||||
Date: Wed, 2 Mar 2022 16:10:50 +0000
|
||||
Subject: [PATCH] V4L2: Add PiSP compressed formats to V4L2
|
||||
|
||||
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
---
|
||||
drivers/media/v4l2-core/v4l2-ioctl.c | 4 ++++
|
||||
include/uapi/linux/videodev2.h | 6 +++++-
|
||||
2 files changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
@@ -1507,6 +1507,10 @@ static void v4l_fill_fmtdesc(struct v4l2
|
||||
case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break;
|
||||
case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break;
|
||||
case V4L2_PIX_FMT_RPI_BE: descr = "PiSP Opaque Format"; break;
|
||||
+ case V4L2_PIX_FMT_PISP_COMP_RGGB:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP_GRBG:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP_GBRG:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP_BGGR: descr = "PiSP Bayer Compressed Format"; break;
|
||||
default:
|
||||
if (fmt->description[0])
|
||||
return;
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -794,7 +794,11 @@ struct v4l2_pix_format {
|
||||
#define V4L2_PIX_FMT_IPU3_SRGGB10 v4l2_fourcc('i', 'p', '3', 'r') /* IPU3 packed 10-bit RGGB bayer */
|
||||
|
||||
/* The pixel format for all our buffers (the precise format is found in the config buffer). */
|
||||
-#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P')
|
||||
+#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP_RGGB v4l2_fourcc('P', 'C', 'R', 'G')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP_GRBG v4l2_fourcc('P', 'C', 'G', 'R')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP_GBRG v4l2_fourcc('P', 'C', 'G', 'B')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP_BGGR v4l2_fourcc('P', 'C', 'B', 'G')
|
||||
|
||||
/* SDR formats - used only for Software Defined Radio devices */
|
||||
#define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
|
@ -0,0 +1,249 @@
|
||||
From c93f469dabdbed822e5abeb5283d79fc9faa858c Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 28 Oct 2022 14:10:34 +0100
|
||||
Subject: [PATCH] dt-binding: mfd: Add binding for Raspberry Pi RP1
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
include/dt-bindings/mfd/rp1.h | 235 ++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 235 insertions(+)
|
||||
create mode 100644 include/dt-bindings/mfd/rp1.h
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/mfd/rp1.h
|
||||
@@ -0,0 +1,235 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+/*
|
||||
+ * This header provides constants for the PY MFD.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _RP1_H
|
||||
+#define _RP1_H
|
||||
+
|
||||
+/* Address map */
|
||||
+#define RP1_SYSINFO_BASE 0x000000
|
||||
+#define RP1_TBMAN_BASE 0x004000
|
||||
+#define RP1_SYSCFG_BASE 0x008000
|
||||
+#define RP1_OTP_BASE 0x00c000
|
||||
+#define RP1_POWER_BASE 0x010000
|
||||
+#define RP1_RESETS_BASE 0x014000
|
||||
+#define RP1_CLOCKS_BANK_DEFAULT_BASE 0x018000
|
||||
+#define RP1_CLOCKS_BANK_VIDEO_BASE 0x01c000
|
||||
+#define RP1_PLL_SYS_BASE 0x020000
|
||||
+#define RP1_PLL_AUDIO_BASE 0x024000
|
||||
+#define RP1_PLL_VIDEO_BASE 0x028000
|
||||
+#define RP1_UART0_BASE 0x030000
|
||||
+#define RP1_UART1_BASE 0x034000
|
||||
+#define RP1_UART2_BASE 0x038000
|
||||
+#define RP1_UART3_BASE 0x03c000
|
||||
+#define RP1_UART4_BASE 0x040000
|
||||
+#define RP1_UART5_BASE 0x044000
|
||||
+#define RP1_SPI8_BASE 0x04c000
|
||||
+#define RP1_SPI0_BASE 0x050000
|
||||
+#define RP1_SPI1_BASE 0x054000
|
||||
+#define RP1_SPI2_BASE 0x058000
|
||||
+#define RP1_SPI3_BASE 0x05c000
|
||||
+#define RP1_SPI4_BASE 0x060000
|
||||
+#define RP1_SPI5_BASE 0x064000
|
||||
+#define RP1_SPI6_BASE 0x068000
|
||||
+#define RP1_SPI7_BASE 0x06c000
|
||||
+#define RP1_I2C0_BASE 0x070000
|
||||
+#define RP1_I2C1_BASE 0x074000
|
||||
+#define RP1_I2C2_BASE 0x078000
|
||||
+#define RP1_I2C3_BASE 0x07c000
|
||||
+#define RP1_I2C4_BASE 0x080000
|
||||
+#define RP1_I2C5_BASE 0x084000
|
||||
+#define RP1_I2C6_BASE 0x088000
|
||||
+#define RP1_AUDIO_IN_BASE 0x090000
|
||||
+#define RP1_AUDIO_OUT_BASE 0x094000
|
||||
+#define RP1_PWM0_BASE 0x098000
|
||||
+#define RP1_PWM1_BASE 0x09c000
|
||||
+#define RP1_I2S0_BASE 0x0a0000
|
||||
+#define RP1_I2S1_BASE 0x0a4000
|
||||
+#define RP1_I2S2_BASE 0x0a8000
|
||||
+#define RP1_TIMER_BASE 0x0ac000
|
||||
+#define RP1_SDIO0_APBS_BASE 0x0b0000
|
||||
+#define RP1_SDIO1_APBS_BASE 0x0b4000
|
||||
+#define RP1_BUSFABRIC_MONITOR_BASE 0x0c0000
|
||||
+#define RP1_BUSFABRIC_AXISHIM_BASE 0x0c4000
|
||||
+#define RP1_ADC_BASE 0x0c8000
|
||||
+#define RP1_IO_BANK0_BASE 0x0d0000
|
||||
+#define RP1_IO_BANK1_BASE 0x0d4000
|
||||
+#define RP1_IO_BANK2_BASE 0x0d8000
|
||||
+#define RP1_SYS_RIO0_BASE 0x0e0000
|
||||
+#define RP1_SYS_RIO1_BASE 0x0e4000
|
||||
+#define RP1_SYS_RIO2_BASE 0x0e8000
|
||||
+#define RP1_PADS_BANK0_BASE 0x0f0000
|
||||
+#define RP1_PADS_BANK1_BASE 0x0f4000
|
||||
+#define RP1_PADS_BANK2_BASE 0x0f8000
|
||||
+#define RP1_PADS_ETH_BASE 0x0fc000
|
||||
+#define RP1_ETH_IP_BASE 0x100000
|
||||
+#define RP1_ETH_CFG_BASE 0x104000
|
||||
+#define RP1_PCIE_APBS_BASE 0x108000
|
||||
+#define RP1_MIPI0_CSIDMA_BASE 0x110000
|
||||
+#define RP1_MIPI0_CSIHOST_BASE 0x114000
|
||||
+#define RP1_MIPI0_DSIDMA_BASE 0x118000
|
||||
+#define RP1_MIPI0_DSIHOST_BASE 0x11c000
|
||||
+#define RP1_MIPI0_MIPICFG_BASE 0x120000
|
||||
+#define RP1_MIPI0_ISP_BASE 0x124000
|
||||
+#define RP1_MIPI1_CSIDMA_BASE 0x128000
|
||||
+#define RP1_MIPI1_CSIHOST_BASE 0x12c000
|
||||
+#define RP1_MIPI1_DSIDMA_BASE 0x130000
|
||||
+#define RP1_MIPI1_DSIHOST_BASE 0x134000
|
||||
+#define RP1_MIPI1_MIPICFG_BASE 0x138000
|
||||
+#define RP1_MIPI1_ISP_BASE 0x13c000
|
||||
+#define RP1_VIDEO_OUT_CFG_BASE 0x140000
|
||||
+#define RP1_VIDEO_OUT_VEC_BASE 0x144000
|
||||
+#define RP1_VIDEO_OUT_DPI_BASE 0x148000
|
||||
+#define RP1_XOSC_BASE 0x150000
|
||||
+#define RP1_WATCHDOG_BASE 0x154000
|
||||
+#define RP1_DMA_TICK_BASE 0x158000
|
||||
+#define RP1_SDIO_CLOCKS_BASE 0x15c000
|
||||
+#define RP1_USBHOST0_APBS_BASE 0x160000
|
||||
+#define RP1_USBHOST1_APBS_BASE 0x164000
|
||||
+#define RP1_ROSC0_BASE 0x168000
|
||||
+#define RP1_ROSC1_BASE 0x16c000
|
||||
+#define RP1_VBUSCTRL_BASE 0x170000
|
||||
+#define RP1_TICKS_BASE 0x174000
|
||||
+#define RP1_PIO_APBS_BASE 0x178000
|
||||
+#define RP1_SDIO0_AHBLS_BASE 0x180000
|
||||
+#define RP1_SDIO1_AHBLS_BASE 0x184000
|
||||
+#define RP1_DMA_BASE 0x188000
|
||||
+#define RP1_RAM_BASE 0x1c0000
|
||||
+#define RP1_RAM_SIZE 0x020000
|
||||
+#define RP1_USBHOST0_AXIS_BASE 0x200000
|
||||
+#define RP1_USBHOST1_AXIS_BASE 0x300000
|
||||
+#define RP1_EXAC_BASE 0x400000
|
||||
+
|
||||
+/* Interrupts */
|
||||
+
|
||||
+#define RP1_INT_IO_BANK0 0
|
||||
+#define RP1_INT_IO_BANK1 1
|
||||
+#define RP1_INT_IO_BANK2 2
|
||||
+#define RP1_INT_AUDIO_IN 3
|
||||
+#define RP1_INT_AUDIO_OUT 4
|
||||
+#define RP1_INT_PWM0 5
|
||||
+#define RP1_INT_ETH 6
|
||||
+#define RP1_INT_I2C0 7
|
||||
+#define RP1_INT_I2C1 8
|
||||
+#define RP1_INT_I2C2 9
|
||||
+#define RP1_INT_I2C3 10
|
||||
+#define RP1_INT_I2C4 11
|
||||
+#define RP1_INT_I2C5 12
|
||||
+#define RP1_INT_I2C6 13
|
||||
+#define RP1_INT_I2S0 14
|
||||
+#define RP1_INT_I2S1 15
|
||||
+#define RP1_INT_I2S2 16
|
||||
+#define RP1_INT_SDIO0 17
|
||||
+#define RP1_INT_SDIO1 18
|
||||
+#define RP1_INT_SPI0 19
|
||||
+#define RP1_INT_SPI1 20
|
||||
+#define RP1_INT_SPI2 21
|
||||
+#define RP1_INT_SPI3 22
|
||||
+#define RP1_INT_SPI4 23
|
||||
+#define RP1_INT_SPI5 24
|
||||
+#define RP1_INT_UART0 25
|
||||
+#define RP1_INT_TIMER_0 26
|
||||
+#define RP1_INT_TIMER_1 27
|
||||
+#define RP1_INT_TIMER_2 28
|
||||
+#define RP1_INT_TIMER_3 29
|
||||
+#define RP1_INT_USBHOST0 30
|
||||
+#define RP1_INT_USBHOST0_0 31
|
||||
+#define RP1_INT_USBHOST0_1 32
|
||||
+#define RP1_INT_USBHOST0_2 33
|
||||
+#define RP1_INT_USBHOST0_3 34
|
||||
+#define RP1_INT_USBHOST1 35
|
||||
+#define RP1_INT_USBHOST1_0 36
|
||||
+#define RP1_INT_USBHOST1_1 37
|
||||
+#define RP1_INT_USBHOST1_2 38
|
||||
+#define RP1_INT_USBHOST1_3 39
|
||||
+#define RP1_INT_DMA 40
|
||||
+#define RP1_INT_PWM1 41
|
||||
+#define RP1_INT_UART1 42
|
||||
+#define RP1_INT_UART2 43
|
||||
+#define RP1_INT_UART3 44
|
||||
+#define RP1_INT_UART4 45
|
||||
+#define RP1_INT_UART5 46
|
||||
+#define RP1_INT_MIPI0 47
|
||||
+#define RP1_INT_MIPI1 48
|
||||
+#define RP1_INT_VIDEO_OUT 49
|
||||
+#define RP1_INT_PIO_0 50
|
||||
+#define RP1_INT_PIO_1 51
|
||||
+#define RP1_INT_ADC_FIFO 52
|
||||
+#define RP1_INT_PCIE_OUT 53
|
||||
+#define RP1_INT_SPI6 54
|
||||
+#define RP1_INT_SPI7 55
|
||||
+#define RP1_INT_SPI8 56
|
||||
+#define RP1_INT_SYSCFG 58
|
||||
+#define RP1_INT_CLOCKS_DEFAULT 59
|
||||
+#define RP1_INT_VBUSCTRL 60
|
||||
+#define RP1_INT_PROC_MISC 57
|
||||
+#define RP1_INT_END 61
|
||||
+
|
||||
+/* DMA peripherals (for pacing) */
|
||||
+#define RP1_DMA_I2C0_RX 0x0
|
||||
+#define RP1_DMA_I2C0_TX 0x1
|
||||
+#define RP1_DMA_I2C1_RX 0x2
|
||||
+#define RP1_DMA_I2C1_TX 0x3
|
||||
+#define RP1_DMA_I2C2_RX 0x4
|
||||
+#define RP1_DMA_I2C2_TX 0x5
|
||||
+#define RP1_DMA_I2C3_RX 0x6
|
||||
+#define RP1_DMA_I2C3_TX 0x7
|
||||
+#define RP1_DMA_I2C4_RX 0x8
|
||||
+#define RP1_DMA_I2C4_TX 0x9
|
||||
+#define RP1_DMA_I2C5_RX 0xa
|
||||
+#define RP1_DMA_I2C5_TX 0xb
|
||||
+#define RP1_DMA_SPI0_RX 0xc
|
||||
+#define RP1_DMA_SPI0_TX 0xd
|
||||
+#define RP1_DMA_SPI1_RX 0xe
|
||||
+#define RP1_DMA_SPI1_TX 0xf
|
||||
+#define RP1_DMA_SPI2_RX 0x10
|
||||
+#define RP1_DMA_SPI2_TX 0x11
|
||||
+#define RP1_DMA_SPI3_RX 0x12
|
||||
+#define RP1_DMA_SPI3_TX 0x13
|
||||
+#define RP1_DMA_SPI4_RX 0x14
|
||||
+#define RP1_DMA_SPI4_TX 0x15
|
||||
+#define RP1_DMA_SPI5_RX 0x16
|
||||
+#define RP1_DMA_SPI5_TX 0x17
|
||||
+#define RP1_DMA_PWM0 0x18
|
||||
+#define RP1_DMA_UART0_RX 0x19
|
||||
+#define RP1_DMA_UART0_TX 0x1a
|
||||
+#define RP1_DMA_AUDIO_IN_CH0 0x1b
|
||||
+#define RP1_DMA_AUDIO_IN_CH1 0x1c
|
||||
+#define RP1_DMA_AUDIO_OUT 0x1d
|
||||
+#define RP1_DMA_PWM1 0x1e
|
||||
+#define RP1_DMA_I2S0_RX 0x1f
|
||||
+#define RP1_DMA_I2S0_TX 0x20
|
||||
+#define RP1_DMA_I2S1_RX 0x21
|
||||
+#define RP1_DMA_I2S1_TX 0x22
|
||||
+#define RP1_DMA_I2S2_RX 0x23
|
||||
+#define RP1_DMA_I2S2_TX 0x24
|
||||
+#define RP1_DMA_UART1_RX 0x25
|
||||
+#define RP1_DMA_UART1_TX 0x26
|
||||
+#define RP1_DMA_UART2_RX 0x27
|
||||
+#define RP1_DMA_UART2_TX 0x28
|
||||
+#define RP1_DMA_UART3_RX 0x29
|
||||
+#define RP1_DMA_UART3_TX 0x2a
|
||||
+#define RP1_DMA_UART4_RX 0x2b
|
||||
+#define RP1_DMA_UART4_TX 0x2c
|
||||
+#define RP1_DMA_UART5_RX 0x2d
|
||||
+#define RP1_DMA_UART5_TX 0x2e
|
||||
+#define RP1_DMA_ADC 0x2f
|
||||
+#define RP1_DMA_DMA_TICK_TICK0 0x30
|
||||
+#define RP1_DMA_DMA_TICK_TICK1 0x31
|
||||
+#define RP1_DMA_SPI6_RX 0x32
|
||||
+#define RP1_DMA_SPI6_TX 0x33
|
||||
+#define RP1_DMA_SPI7_RX 0x34
|
||||
+#define RP1_DMA_SPI7_TX 0x35
|
||||
+#define RP1_DMA_SPI8_RX 0x36
|
||||
+#define RP1_DMA_SPI8_TX 0x37
|
||||
+#define RP1_DMA_PIO_CH0_TX 0x38
|
||||
+#define RP1_DMA_PIO_CH0_RX 0x39
|
||||
+#define RP1_DMA_PIO_CH1_TX 0x3a
|
||||
+#define RP1_DMA_PIO_CH1_RX 0x3b
|
||||
+#define RP1_DMA_PIO_CH2_TX 0x3c
|
||||
+#define RP1_DMA_PIO_CH2_RX 0x3d
|
||||
+#define RP1_DMA_PIO_CH3_TX 0x3e
|
||||
+#define RP1_DMA_PIO_CH3_RX 0x3f
|
||||
+
|
||||
+#endif
|
@ -0,0 +1,442 @@
|
||||
From 7196a12b94e90225686e6c34cdf65a583214f7a5 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 10 Oct 2022 14:21:50 +0100
|
||||
Subject: [PATCH] mfd: Add rp1 driver
|
||||
|
||||
RP1 is a multifunction PCIe device that exposes a range of
|
||||
peripherals.
|
||||
Add the parent driver to manage these.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/mfd/Kconfig | 11 ++
|
||||
drivers/mfd/Makefile | 1 +
|
||||
drivers/mfd/rp1.c | 367 +++++++++++++++++++++++++++++++++++
|
||||
include/linux/rp1_platform.h | 20 ++
|
||||
4 files changed, 399 insertions(+)
|
||||
create mode 100644 drivers/mfd/rp1.c
|
||||
create mode 100644 include/linux/rp1_platform.h
|
||||
|
||||
--- a/drivers/mfd/Kconfig
|
||||
+++ b/drivers/mfd/Kconfig
|
||||
@@ -2252,6 +2252,17 @@ config MFD_INTEL_M10_BMC
|
||||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
+config MFD_RP1
|
||||
+ tristate "RP1 MFD driver"
|
||||
+ depends on PCI
|
||||
+ select MFD_CORE
|
||||
+ help
|
||||
+ Support for the RP1 peripheral chip.
|
||||
+
|
||||
+ This driver provides support for the Raspberry Pi RP1 peripheral chip.
|
||||
+ It is responsible for enabling the Device Tree node once the PCIe endpoint
|
||||
+ has been configured, and handling interrupts.
|
||||
+
|
||||
config MFD_RSMU_I2C
|
||||
tristate "Renesas Synchronization Management Unit with I2C"
|
||||
depends on I2C && OF
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -273,6 +273,7 @@ obj-$(CONFIG_MFD_RPISENSE_CORE) += rpise
|
||||
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
|
||||
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
|
||||
obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o
|
||||
+obj-$(CONFIG_MFD_RP1) += rp1.o
|
||||
|
||||
obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
|
||||
obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/rp1.c
|
||||
@@ -0,0 +1,367 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Copyright (c) 2018-22 Raspberry Pi Ltd.
|
||||
+ * All rights reserved.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/clkdev.h>
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include <linux/completion.h>
|
||||
+#include <linux/etherdevice.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/irq.h>
|
||||
+#include <linux/irqchip/chained_irq.h>
|
||||
+#include <linux/irqdomain.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/mmc/host.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/msi.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/pci.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/rp1_platform.h>
|
||||
+#include <linux/reset.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include <dt-bindings/mfd/rp1.h>
|
||||
+
|
||||
+/* TO DO:
|
||||
+ * 1. Occasional shutdown crash - RP1 being closed before its children?
|
||||
+ * 2. DT mode interrupt handling.
|
||||
+ */
|
||||
+
|
||||
+#define RP1_DRIVER_NAME "rp1"
|
||||
+
|
||||
+#define PCI_VENDOR_ID_RPI 0x1de4
|
||||
+#define PCI_DEVICE_ID_RP1_C0 0x0001
|
||||
+#define PCI_DEVICE_REV_RP1_C0 2
|
||||
+
|
||||
+#define RP1_ACTUAL_IRQS RP1_INT_END
|
||||
+#define RP1_IRQS RP1_ACTUAL_IRQS
|
||||
+
|
||||
+#define RP1_SYSCLK_RATE 200000000
|
||||
+#define RP1_SYSCLK_FPGA_RATE 60000000
|
||||
+
|
||||
+// Don't want to include the whole sysinfo reg header
|
||||
+#define SYSINFO_CHIP_ID_OFFSET 0x00000000
|
||||
+#define SYSINFO_PLATFORM_OFFSET 0x00000004
|
||||
+
|
||||
+#define REG_RW 0x000
|
||||
+#define REG_SET 0x800
|
||||
+#define REG_CLR 0xc00
|
||||
+
|
||||
+// MSIX CFG registers start at 0x8
|
||||
+#define MSIX_CFG(x) (0x8 + (4 * (x)))
|
||||
+
|
||||
+#define MSIX_CFG_IACK_EN BIT(3)
|
||||
+#define MSIX_CFG_IACK BIT(2)
|
||||
+#define MSIX_CFG_TEST BIT(1)
|
||||
+#define MSIX_CFG_ENABLE BIT(0)
|
||||
+
|
||||
+#define INTSTATL 0x108
|
||||
+#define INTSTATH 0x10c
|
||||
+
|
||||
+struct rp1_dev {
|
||||
+ struct pci_dev *pdev;
|
||||
+ struct device *dev;
|
||||
+ resource_size_t bar_start;
|
||||
+ resource_size_t bar_end;
|
||||
+ struct clk *sys_clk;
|
||||
+ struct irq_domain *domain;
|
||||
+ struct irq_data *pcie_irqds[64];
|
||||
+ void __iomem *msix_cfg_regs;
|
||||
+};
|
||||
+
|
||||
+static bool rp1_level_triggered_irq[RP1_ACTUAL_IRQS] = { 0 };
|
||||
+
|
||||
+static struct rp1_dev *g_rp1;
|
||||
+static u32 g_chip_id, g_platform;
|
||||
+
|
||||
+static void dump_bar(struct pci_dev *pdev, unsigned int bar)
|
||||
+{
|
||||
+ dev_info(&pdev->dev,
|
||||
+ "bar%d len 0x%llx, start 0x%llx, end 0x%llx, flags, 0x%lx\n",
|
||||
+ bar,
|
||||
+ pci_resource_len(pdev, bar),
|
||||
+ pci_resource_start(pdev, bar),
|
||||
+ pci_resource_end(pdev, bar),
|
||||
+ pci_resource_flags(pdev, bar));
|
||||
+}
|
||||
+
|
||||
+static void msix_cfg_set(struct rp1_dev *rp1, unsigned int hwirq, u32 value)
|
||||
+{
|
||||
+ writel(value, rp1->msix_cfg_regs + REG_SET + MSIX_CFG(hwirq));
|
||||
+}
|
||||
+
|
||||
+static void msix_cfg_clr(struct rp1_dev *rp1, unsigned int hwirq, u32 value)
|
||||
+{
|
||||
+ writel(value, rp1->msix_cfg_regs + REG_CLR + MSIX_CFG(hwirq));
|
||||
+}
|
||||
+
|
||||
+static void rp1_mask_irq(struct irq_data *irqd)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = irqd->domain->host_data;
|
||||
+ struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq];
|
||||
+
|
||||
+ pci_msi_mask_irq(pcie_irqd);
|
||||
+}
|
||||
+
|
||||
+static void rp1_unmask_irq(struct irq_data *irqd)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = irqd->domain->host_data;
|
||||
+ struct irq_data *pcie_irqd = rp1->pcie_irqds[irqd->hwirq];
|
||||
+
|
||||
+ pci_msi_unmask_irq(pcie_irqd);
|
||||
+}
|
||||
+
|
||||
+static int rp1_irq_set_type(struct irq_data *irqd, unsigned int type)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = irqd->domain->host_data;
|
||||
+ unsigned int hwirq = (unsigned int)irqd->hwirq;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case IRQ_TYPE_LEVEL_HIGH:
|
||||
+ dev_dbg(rp1->dev, "MSIX IACK EN for irq %d\n", hwirq);
|
||||
+ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK_EN);
|
||||
+ rp1_level_triggered_irq[hwirq] = true;
|
||||
+ break;
|
||||
+ case IRQ_TYPE_EDGE_RISING:
|
||||
+ msix_cfg_clr(rp1, hwirq, MSIX_CFG_IACK_EN);
|
||||
+ rp1_level_triggered_irq[hwirq] = false;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = -EINVAL;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static struct irq_chip rp1_irq_chip = {
|
||||
+ .name = "rp1_irq_chip",
|
||||
+ .irq_mask = rp1_mask_irq,
|
||||
+ .irq_unmask = rp1_unmask_irq,
|
||||
+ .irq_set_type = rp1_irq_set_type,
|
||||
+};
|
||||
+
|
||||
+static void rp1_chained_handle_irq(struct irq_desc *desc)
|
||||
+{
|
||||
+ struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
+ struct rp1_dev *rp1 = desc->irq_data.chip_data;
|
||||
+ unsigned int hwirq = desc->irq_data.hwirq & 0x3f;
|
||||
+ int new_irq;
|
||||
+
|
||||
+ rp1 = g_rp1;
|
||||
+
|
||||
+ chained_irq_enter(chip, desc);
|
||||
+
|
||||
+ new_irq = irq_linear_revmap(rp1->domain, hwirq);
|
||||
+ generic_handle_irq(new_irq);
|
||||
+ if (rp1_level_triggered_irq[hwirq])
|
||||
+ msix_cfg_set(rp1, hwirq, MSIX_CFG_IACK);
|
||||
+
|
||||
+ chained_irq_exit(chip, desc);
|
||||
+}
|
||||
+
|
||||
+static int rp1_irq_xlate(struct irq_domain *d, struct device_node *node,
|
||||
+ const u32 *intspec, unsigned int intsize,
|
||||
+ unsigned long *out_hwirq, unsigned int *out_type)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = d->host_data;
|
||||
+ struct irq_data *pcie_irqd;
|
||||
+ unsigned long hwirq;
|
||||
+ int pcie_irq;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = irq_domain_xlate_twocell(d, node, intspec, intsize,
|
||||
+ &hwirq, out_type);
|
||||
+ if (!ret) {
|
||||
+ pcie_irq = pci_irq_vector(rp1->pdev, hwirq);
|
||||
+ pcie_irqd = irq_get_irq_data(pcie_irq);
|
||||
+ rp1->pcie_irqds[hwirq] = pcie_irqd;
|
||||
+ *out_hwirq = hwirq;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rp1_irq_activate(struct irq_domain *d, struct irq_data *irqd,
|
||||
+ bool reserve)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = d->host_data;
|
||||
+ struct irq_data *pcie_irqd;
|
||||
+
|
||||
+ pcie_irqd = rp1->pcie_irqds[irqd->hwirq];
|
||||
+ msix_cfg_set(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE);
|
||||
+ return irq_domain_activate_irq(pcie_irqd, reserve);
|
||||
+}
|
||||
+
|
||||
+static void rp1_irq_deactivate(struct irq_domain *d, struct irq_data *irqd)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = d->host_data;
|
||||
+ struct irq_data *pcie_irqd;
|
||||
+
|
||||
+ pcie_irqd = rp1->pcie_irqds[irqd->hwirq];
|
||||
+ msix_cfg_clr(rp1, (unsigned int)irqd->hwirq, MSIX_CFG_ENABLE);
|
||||
+ return irq_domain_deactivate_irq(pcie_irqd);
|
||||
+}
|
||||
+
|
||||
+static const struct irq_domain_ops rp1_domain_ops = {
|
||||
+ .xlate = rp1_irq_xlate,
|
||||
+ .activate = rp1_irq_activate,
|
||||
+ .deactivate = rp1_irq_deactivate,
|
||||
+};
|
||||
+
|
||||
+static inline dma_addr_t rp1_io_to_phys(struct rp1_dev *rp1, unsigned int offset)
|
||||
+{
|
||||
+ return rp1->bar_start + offset;
|
||||
+}
|
||||
+
|
||||
+static u32 rp1_reg_read(struct rp1_dev *rp1, unsigned int base_addr, u32 offset)
|
||||
+{
|
||||
+ dma_addr_t phys = rp1_io_to_phys(rp1, base_addr);
|
||||
+ void __iomem *regblock = ioremap(phys, 0x1000);
|
||||
+ u32 value = readl(regblock + offset);
|
||||
+
|
||||
+ iounmap(regblock);
|
||||
+ return value;
|
||||
+}
|
||||
+
|
||||
+void rp1_get_platform(u32 *chip_id, u32 *platform)
|
||||
+{
|
||||
+ if (chip_id)
|
||||
+ *chip_id = g_chip_id;
|
||||
+ if (platform)
|
||||
+ *platform = g_platform;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rp1_get_platform);
|
||||
+
|
||||
+static int rp1_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
+{
|
||||
+ struct reset_control *reset;
|
||||
+ struct platform_device *pcie_pdev;
|
||||
+ struct device_node *rp1_node;
|
||||
+ struct rp1_dev *rp1;
|
||||
+ int err = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ reset = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(reset))
|
||||
+ return PTR_ERR(reset);
|
||||
+ reset_control_reset(reset);
|
||||
+
|
||||
+ dump_bar(pdev, 0);
|
||||
+ dump_bar(pdev, 1);
|
||||
+
|
||||
+ if (pci_resource_len(pdev, 1) <= 0x10000) {
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "Not initialised - is the firmware running?\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* enable pci device */
|
||||
+ err = pcim_enable_device(pdev);
|
||||
+ if (err < 0) {
|
||||
+ dev_err(&pdev->dev, "Enabling PCI device has failed: %d",
|
||||
+ err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ pci_set_master(pdev);
|
||||
+
|
||||
+ err = pci_alloc_irq_vectors(pdev, RP1_IRQS, RP1_IRQS,
|
||||
+ PCI_IRQ_MSIX);
|
||||
+ if (err != RP1_IRQS) {
|
||||
+ dev_err(&pdev->dev, "pci_alloc_irq_vectors failed - %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ rp1 = devm_kzalloc(&pdev->dev, sizeof(*rp1), GFP_KERNEL);
|
||||
+ if (!rp1)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ rp1->pdev = pdev;
|
||||
+ rp1->dev = &pdev->dev;
|
||||
+
|
||||
+ pci_set_drvdata(pdev, rp1);
|
||||
+
|
||||
+ rp1->bar_start = pci_resource_start(pdev, 1);
|
||||
+ rp1->bar_end = pci_resource_end(pdev, 1);
|
||||
+
|
||||
+ // Get chip id
|
||||
+ g_chip_id = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_CHIP_ID_OFFSET);
|
||||
+ g_platform = rp1_reg_read(rp1, RP1_SYSINFO_BASE, SYSINFO_PLATFORM_OFFSET);
|
||||
+ dev_info(&pdev->dev, "chip_id 0x%x%s\n", g_chip_id,
|
||||
+ (g_platform & RP1_PLATFORM_FPGA) ? " FPGA" : "");
|
||||
+ if (g_chip_id != RP1_C0_CHIP_ID) {
|
||||
+ dev_err(&pdev->dev, "wrong chip id (%x)\n", g_chip_id);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ rp1_node = of_find_node_by_name(NULL, "rp1");
|
||||
+ if (!rp1_node) {
|
||||
+ dev_err(&pdev->dev, "failed to find RP1 DT node\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ pcie_pdev = of_find_device_by_node(rp1_node->parent);
|
||||
+ rp1->domain = irq_domain_add_linear(rp1_node, RP1_IRQS,
|
||||
+ &rp1_domain_ops, rp1);
|
||||
+
|
||||
+ g_rp1 = rp1;
|
||||
+
|
||||
+ /* TODO can this go in the rp1 device tree entry? */
|
||||
+ rp1->msix_cfg_regs = ioremap(rp1_io_to_phys(rp1, RP1_PCIE_APBS_BASE), 0x1000);
|
||||
+
|
||||
+ for (i = 0; i < RP1_IRQS; i++) {
|
||||
+ int irq = irq_create_mapping(rp1->domain, i);
|
||||
+
|
||||
+ if (irq < 0) {
|
||||
+ dev_err(&pdev->dev, "failed to create irq mapping\n");
|
||||
+ return irq;
|
||||
+ }
|
||||
+
|
||||
+ irq_set_chip_data(irq, rp1);
|
||||
+ irq_set_chip_and_handler(irq, &rp1_irq_chip, handle_level_irq);
|
||||
+ irq_set_probe(irq);
|
||||
+ irq_set_chained_handler(pci_irq_vector(pdev, i),
|
||||
+ rp1_chained_handle_irq);
|
||||
+ }
|
||||
+
|
||||
+ if (rp1_node)
|
||||
+ of_platform_populate(rp1_node, NULL, NULL, &pcie_pdev->dev);
|
||||
+
|
||||
+ of_node_put(rp1_node);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void rp1_remove(struct pci_dev *pdev)
|
||||
+{
|
||||
+ struct rp1_dev *rp1 = pci_get_drvdata(pdev);
|
||||
+
|
||||
+ mfd_remove_devices(&pdev->dev);
|
||||
+
|
||||
+ clk_unregister(rp1->sys_clk);
|
||||
+}
|
||||
+
|
||||
+static const struct pci_device_id dev_id_table[] = {
|
||||
+ { PCI_DEVICE(PCI_VENDOR_ID_RPI, PCI_DEVICE_ID_RP1_C0), },
|
||||
+ { 0, }
|
||||
+};
|
||||
+
|
||||
+static struct pci_driver rp1_driver = {
|
||||
+ .name = RP1_DRIVER_NAME,
|
||||
+ .id_table = dev_id_table,
|
||||
+ .probe = rp1_probe,
|
||||
+ .remove = rp1_remove,
|
||||
+};
|
||||
+
|
||||
+module_pci_driver(rp1_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
|
||||
+MODULE_DESCRIPTION("RP1 wrapper");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- /dev/null
|
||||
+++ b/include/linux/rp1_platform.h
|
||||
@@ -0,0 +1,20 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+/*
|
||||
+ * Copyright (c) 2021-2022 Raspberry Pi Ltd.
|
||||
+ * All rights reserved.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _RP1_PLATFORM_H
|
||||
+#define _RP1_PLATFORM_H
|
||||
+
|
||||
+#include <vdso/bits.h>
|
||||
+
|
||||
+#define RP1_B0_CHIP_ID 0x10001927
|
||||
+#define RP1_C0_CHIP_ID 0x20001927
|
||||
+
|
||||
+#define RP1_PLATFORM_ASIC BIT(1)
|
||||
+#define RP1_PLATFORM_FPGA BIT(0)
|
||||
+
|
||||
+void rp1_get_platform(u32 *chip_id, u32 *platform);
|
||||
+
|
||||
+#endif
|
@ -0,0 +1,65 @@
|
||||
From 00ff2819eb852b54fe22e7181646e40d560576dc Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 28 Oct 2022 14:12:18 +0100
|
||||
Subject: [PATCH] dt-bindings: clock: Add bindings for Raspberry Pi RP1
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
include/dt-bindings/clock/rp1.h | 51 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 51 insertions(+)
|
||||
create mode 100644 include/dt-bindings/clock/rp1.h
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/clock/rp1.h
|
||||
@@ -0,0 +1,51 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+/*
|
||||
+ * Copyright (C) 2021 Raspberry Pi Ltd.
|
||||
+ */
|
||||
+
|
||||
+#define RP1_PLL_SYS_CORE 0
|
||||
+#define RP1_PLL_AUDIO_CORE 1
|
||||
+#define RP1_PLL_VIDEO_CORE 2
|
||||
+
|
||||
+#define RP1_PLL_SYS 3
|
||||
+#define RP1_PLL_AUDIO 4
|
||||
+#define RP1_PLL_VIDEO 5
|
||||
+
|
||||
+#define RP1_PLL_SYS_PRI_PH 6
|
||||
+#define RP1_PLL_SYS_SEC_PH 7
|
||||
+
|
||||
+#define RP1_PLL_SYS_SEC 8
|
||||
+#define RP1_PLL_AUDIO_SEC 9
|
||||
+#define RP1_PLL_VIDEO_SEC 10
|
||||
+
|
||||
+#define RP1_CLK_SYS 11
|
||||
+#define RP1_CLK_SLOW_SYS 12
|
||||
+#define RP1_CLK_DMA 13
|
||||
+#define RP1_CLK_UART 14
|
||||
+#define RP1_CLK_ETH 15
|
||||
+#define RP1_CLK_PWM0 16
|
||||
+#define RP1_CLK_PWM1 17
|
||||
+#define RP1_CLK_AUDIO_IN 18
|
||||
+#define RP1_CLK_AUDIO_OUT 19
|
||||
+#define RP1_CLK_I2S 20
|
||||
+#define RP1_CLK_MIPI0_CFG 21
|
||||
+#define RP1_CLK_MIPI1_CFG 22
|
||||
+#define RP1_CLK_PCIE_AUX 23
|
||||
+#define RP1_CLK_USBH0_MICROFRAME 24
|
||||
+#define RP1_CLK_USBH1_MICROFRAME 25
|
||||
+#define RP1_CLK_USBH0_SUSPEND 26
|
||||
+#define RP1_CLK_USBH1_SUSPEND 27
|
||||
+#define RP1_CLK_ETH_TSU 28
|
||||
+#define RP1_CLK_ADC 29
|
||||
+#define RP1_CLK_SDIO_TIMER 30
|
||||
+#define RP1_CLK_SDIO_ALT_SRC 31
|
||||
+#define RP1_CLK_GP0 32
|
||||
+#define RP1_CLK_GP1 33
|
||||
+#define RP1_CLK_GP2 34
|
||||
+#define RP1_CLK_GP3 35
|
||||
+#define RP1_CLK_GP4 36
|
||||
+#define RP1_CLK_GP5 37
|
||||
+#define RP1_CLK_VEC 38
|
||||
+#define RP1_CLK_DPI 39
|
||||
+#define RP1_CLK_MIPI0_DPI 40
|
||||
+#define RP1_CLK_MIPI1_DPI 41
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,60 @@
|
||||
From 19b934ce3763c9465c5c80302f7c142d30b75869 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 28 Oct 2022 14:13:30 +0100
|
||||
Subject: [PATCH] dt-bindings: pinctrl: Add bindings for Raspberry Pi RP1
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
include/dt-bindings/pinctrl/rp1.h | 46 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 46 insertions(+)
|
||||
create mode 100644 include/dt-bindings/pinctrl/rp1.h
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/dt-bindings/pinctrl/rp1.h
|
||||
@@ -0,0 +1,46 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+/*
|
||||
+ * Header providing constants for RP1 pinctrl bindings.
|
||||
+ *
|
||||
+ * Copyright (C) 2019-2022 Raspberry Pi Ltd.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __DT_BINDINGS_PINCTRL_RP1_H__
|
||||
+#define __DT_BINDINGS_PINCTRL_RP1_H__
|
||||
+
|
||||
+/* brcm,function property */
|
||||
+#define RP1_FSEL_GPIO_IN 0
|
||||
+#define RP1_FSEL_GPIO_OUT 1
|
||||
+#define RP1_FSEL_ALT0_LEGACY 4
|
||||
+#define RP1_FSEL_ALT1_LEGACY 5
|
||||
+#define RP1_FSEL_ALT2_LEGACY 6
|
||||
+#define RP1_FSEL_ALT3_LEGACY 7
|
||||
+#define RP1_FSEL_ALT4_LEGACY 3
|
||||
+#define RP1_FSEL_ALT5_LEGACY 2
|
||||
+#define RP1_FSEL_ALT0 0x08
|
||||
+#define RP1_FSEL_ALT0INV 0x09
|
||||
+#define RP1_FSEL_ALT1 0x0a
|
||||
+#define RP1_FSEL_ALT1INV 0x0b
|
||||
+#define RP1_FSEL_ALT2 0x0c
|
||||
+#define RP1_FSEL_ALT2INV 0x0d
|
||||
+#define RP1_FSEL_ALT3 0x0e
|
||||
+#define RP1_FSEL_ALT3INV 0x0f
|
||||
+#define RP1_FSEL_ALT4 0x10
|
||||
+#define RP1_FSEL_ALT4INV 0x11
|
||||
+#define RP1_FSEL_ALT5 0x12
|
||||
+#define RP1_FSEL_ALT5INV 0x13
|
||||
+#define RP1_FSEL_ALT6 0x14
|
||||
+#define RP1_FSEL_ALT6INV 0x15
|
||||
+#define RP1_FSEL_ALT7 0x16
|
||||
+#define RP1_FSEL_ALT7INV 0x17
|
||||
+#define RP1_FSEL_ALT8 0x18
|
||||
+#define RP1_FSEL_ALT8INV 0x19
|
||||
+#define RP1_FSEL_NONE 0x1a
|
||||
+
|
||||
+/* brcm,pull property */
|
||||
+#define RP1_PUD_OFF 0
|
||||
+#define RP1_PUD_DOWN 1
|
||||
+#define RP1_PUD_UP 2
|
||||
+#define RP1_PUD_KEEP 3
|
||||
+
|
||||
+#endif /* __DT_BINDINGS_PINCTRL_RP1_H__ */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,129 @@
|
||||
From f88da9e21d8eff58eeb9280ae96bf9593121d8eb Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 12 Oct 2022 13:24:51 +0100
|
||||
Subject: [PATCH] serial: pl011: rp1 uart support
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/tty/serial/amba-pl011.c | 96 +++++++++++++++++++++++++++++++++
|
||||
1 file changed, 96 insertions(+)
|
||||
|
||||
--- a/drivers/tty/serial/amba-pl011.c
|
||||
+++ b/drivers/tty/serial/amba-pl011.c
|
||||
@@ -152,6 +152,20 @@ static const struct vendor_data vendor_s
|
||||
.fixed_options = true,
|
||||
};
|
||||
|
||||
+static struct vendor_data vendor_arm_axi = {
|
||||
+ .reg_offset = pl011_std_offsets,
|
||||
+ .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
|
||||
+ .fr_busy = UART01x_FR_BUSY,
|
||||
+ .fr_dsr = UART01x_FR_DSR,
|
||||
+ .fr_cts = UART01x_FR_CTS,
|
||||
+ .fr_ri = UART011_FR_RI,
|
||||
+ .oversampling = false,
|
||||
+ .dma_threshold = false,
|
||||
+ .cts_event_workaround = false,
|
||||
+ .always_enabled = false,
|
||||
+ .fixed_options = false,
|
||||
+};
|
||||
+
|
||||
#ifdef CONFIG_ACPI_SPCR_TABLE
|
||||
static const struct vendor_data vendor_qdt_qdf2400_e44 = {
|
||||
.reg_offset = pl011_std_offsets,
|
||||
@@ -2972,6 +2986,86 @@ static struct platform_driver arm_sbsa_u
|
||||
},
|
||||
};
|
||||
|
||||
+static int pl011_axi_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct uart_amba_port *uap;
|
||||
+ struct vendor_data *vendor = &vendor_arm_axi;
|
||||
+ struct resource *r;
|
||||
+ unsigned int periphid;
|
||||
+ int portnr, ret, irq;
|
||||
+
|
||||
+ portnr = pl011_find_free_port();
|
||||
+ if (portnr < 0)
|
||||
+ return portnr;
|
||||
+
|
||||
+ uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!uap)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ uap->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(uap->clk))
|
||||
+ return PTR_ERR(uap->clk);
|
||||
+
|
||||
+ if (of_property_read_bool(pdev->dev.of_node, "cts-event-workaround")) {
|
||||
+ vendor->cts_event_workaround = true;
|
||||
+ dev_info(&pdev->dev, "cts_event_workaround enabled\n");
|
||||
+ }
|
||||
+
|
||||
+ irq = platform_get_irq(pdev, 0);
|
||||
+ if (irq < 0)
|
||||
+ return irq;
|
||||
+
|
||||
+ periphid = 0x00241011; /* A safe default */
|
||||
+ of_property_read_u32(pdev->dev.of_node, "arm,primecell-periphid",
|
||||
+ &periphid);
|
||||
+
|
||||
+ uap->reg_offset = vendor->reg_offset;
|
||||
+ uap->vendor = vendor;
|
||||
+ uap->fifosize = (AMBA_REV_BITS(periphid) < 3) ? 16 : 32;
|
||||
+ uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
|
||||
+ uap->port.irq = irq;
|
||||
+ uap->port.ops = &amba_pl011_pops;
|
||||
+
|
||||
+ snprintf(uap->type, sizeof(uap->type), "PL011 AXI");
|
||||
+
|
||||
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+
|
||||
+ ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, uap);
|
||||
+
|
||||
+ return pl011_register_port(uap);
|
||||
+}
|
||||
+
|
||||
+static int pl011_axi_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct uart_amba_port *uap = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ uart_remove_one_port(&amba_reg, &uap->port);
|
||||
+ pl011_unregister_port(uap);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id pl011_axi_of_match[] = {
|
||||
+ { .compatible = "arm,pl011-axi" },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, pl011_axi_of_match);
|
||||
+
|
||||
+static struct platform_driver pl011_axi_platform_driver = {
|
||||
+ .probe = pl011_axi_probe,
|
||||
+ .remove = pl011_axi_remove,
|
||||
+ .driver = {
|
||||
+ .name = "pl011-axi",
|
||||
+ .pm = &pl011_dev_pm_ops,
|
||||
+ .of_match_table = of_match_ptr(pl011_axi_of_match),
|
||||
+ .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
static const struct amba_id pl011_ids[] = {
|
||||
{
|
||||
.id = 0x00041011,
|
||||
@@ -3005,6 +3099,8 @@ static int __init pl011_init(void)
|
||||
|
||||
if (platform_driver_register(&arm_sbsa_uart_platform_driver))
|
||||
pr_warn("could not register SBSA UART platform driver\n");
|
||||
+ if (platform_driver_register(&pl011_axi_platform_driver))
|
||||
+ pr_warn("could not register PL011 AXI platform driver\n");
|
||||
return amba_driver_register(&pl011_driver);
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
From 4a5ac516ca0a820e7c006ae408872009e37e114b Mon Sep 17 00:00:00 2001
|
||||
From: Liam Fraser <liam@raspberrypi.com>
|
||||
Date: Thu, 14 Mar 2019 16:01:26 +0000
|
||||
Subject: [PATCH] mmc: sdhci-of-dwcmshc: define sdio timeout clocks
|
||||
|
||||
Signed-off-by: Liam Fraser <liam@raspberrypi.com>
|
||||
---
|
||||
drivers/mmc/host/sdhci-of-dwcmshc.c | 12 ++++++++++++
|
||||
drivers/mmc/host/sdhci-pltfm.c | 8 ++++++++
|
||||
drivers/mmc/host/sdhci-pltfm.h | 3 +++
|
||||
3 files changed, 23 insertions(+)
|
||||
|
||||
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
@@ -330,6 +330,7 @@ static const struct sdhci_ops sdhci_dwcm
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
.get_max_clock = dwcmshc_get_max_clock,
|
||||
+ .get_timeout_clock = sdhci_pltfm_clk_get_timeout_clock,
|
||||
.reset = sdhci_reset,
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
};
|
||||
@@ -500,6 +501,16 @@ static int dwcmshc_probe(struct platform
|
||||
clk_prepare_enable(priv->bus_clk);
|
||||
}
|
||||
|
||||
+ pltfm_host->timeout_clk = devm_clk_get(&pdev->dev, "timeout");
|
||||
+ if (IS_ERR(pltfm_host->timeout_clk)) {
|
||||
+ err = PTR_ERR(pltfm_host->timeout_clk);
|
||||
+ dev_err(&pdev->dev, "failed to get timeout clk: %d\n", err);
|
||||
+ goto free_pltfm;
|
||||
+ }
|
||||
+ err = clk_prepare_enable(pltfm_host->timeout_clk);
|
||||
+ if (err)
|
||||
+ goto free_pltfm;
|
||||
+
|
||||
err = mmc_of_parse(host->mmc);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
@@ -550,6 +561,7 @@ err_setup_host:
|
||||
sdhci_cleanup_host(host);
|
||||
err_clk:
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
+ clk_disable_unprepare(pltfm_host->timeout_clk);
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
|
||||
--- a/drivers/mmc/host/sdhci-pltfm.c
|
||||
+++ b/drivers/mmc/host/sdhci-pltfm.c
|
||||
@@ -33,6 +33,14 @@ unsigned int sdhci_pltfm_clk_get_max_clo
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
|
||||
|
||||
+unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host)
|
||||
+{
|
||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
+
|
||||
+ return clk_get_rate(pltfm_host->timeout_clk);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_timeout_clock);
|
||||
+
|
||||
static const struct sdhci_ops sdhci_pltfm_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
--- a/drivers/mmc/host/sdhci-pltfm.h
|
||||
+++ b/drivers/mmc/host/sdhci-pltfm.h
|
||||
@@ -20,6 +20,7 @@ struct sdhci_pltfm_data {
|
||||
|
||||
struct sdhci_pltfm_host {
|
||||
struct clk *clk;
|
||||
+ struct clk *timeout_clk;
|
||||
|
||||
/* migrate from sdhci_of_host */
|
||||
unsigned int clock;
|
||||
@@ -106,6 +107,8 @@ extern int sdhci_pltfm_unregister(struct
|
||||
|
||||
extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
|
||||
|
||||
+extern unsigned int sdhci_pltfm_clk_get_timeout_clock(struct sdhci_host *host);
|
||||
+
|
||||
static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
|
||||
{
|
||||
return host->private;
|
@ -0,0 +1,83 @@
|
||||
From 14a43b3fd43bf9b230f93d1eba276d40aac969ba Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 12 Oct 2022 14:07:32 +0100
|
||||
Subject: [PATCH] mmc: sdhci-of-dwcmshc: rp1 sdio changes
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/mmc/host/sdhci-of-dwcmshc.c | 29 ++++++++++++++++++++++++++---
|
||||
1 file changed, 26 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
|
||||
@@ -87,6 +87,7 @@ struct rk35xx_priv {
|
||||
|
||||
struct dwcmshc_priv {
|
||||
struct clk *bus_clk;
|
||||
+ struct clk *sdio_clk;
|
||||
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
|
||||
void *priv; /* pointer to SoC private stuff */
|
||||
};
|
||||
@@ -114,6 +115,17 @@ static void dwcmshc_adma_write_desc(stru
|
||||
sdhci_adma_write_desc(host, desc, addr, len, cmd);
|
||||
}
|
||||
|
||||
+static void dwcmshc_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
+{
|
||||
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
+
|
||||
+ if (priv->sdio_clk)
|
||||
+ clk_set_rate(priv->sdio_clk, clock);
|
||||
+
|
||||
+ sdhci_set_clock(host, clock);
|
||||
+}
|
||||
+
|
||||
static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
@@ -326,7 +338,7 @@ static void rk35xx_sdhci_reset(struct sd
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_dwcmshc_ops = {
|
||||
- .set_clock = sdhci_set_clock,
|
||||
+ .set_clock = dwcmshc_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
.get_max_clock = dwcmshc_get_max_clock,
|
||||
@@ -346,8 +358,10 @@ static const struct sdhci_ops sdhci_dwcm
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||
.ops = &sdhci_dwcmshc_ops,
|
||||
- .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
||||
- .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION,
|
||||
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
+ SDHCI_QUIRK2_BROKEN_HS200,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
@@ -499,6 +513,14 @@ static int dwcmshc_probe(struct platform
|
||||
priv->bus_clk = devm_clk_get(dev, "bus");
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_prepare_enable(priv->bus_clk);
|
||||
+
|
||||
+ pltfm_host->timeout_clk = devm_clk_get(dev, "timeout");
|
||||
+ if (!IS_ERR(pltfm_host->timeout_clk))
|
||||
+ err = clk_prepare_enable(pltfm_host->timeout_clk);
|
||||
+ if (err)
|
||||
+ goto free_pltfm;
|
||||
+
|
||||
+ priv->sdio_clk = devm_clk_get_optional(&pdev->dev, "sdio");
|
||||
}
|
||||
|
||||
pltfm_host->timeout_clk = devm_clk_get(&pdev->dev, "timeout");
|
||||
@@ -516,6 +538,7 @@ static int dwcmshc_probe(struct platform
|
||||
goto err_clk;
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
+ sdhci_enable_v4_mode(host);
|
||||
|
||||
priv->vendor_specific_area1 =
|
||||
sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
|
@ -0,0 +1,641 @@
|
||||
From b427cc1a83404f48b12dec2efbef076b38df6218 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 12 Oct 2022 14:20:07 +0100
|
||||
Subject: [PATCH] clk: rp1: Add sdio-clk driver
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/clk/Kconfig | 6 +
|
||||
drivers/clk/Makefile | 1 +
|
||||
drivers/clk/clk-rp1-sdio.c | 600 +++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 607 insertions(+)
|
||||
create mode 100644 drivers/clk/clk-rp1-sdio.c
|
||||
|
||||
--- a/drivers/clk/Kconfig
|
||||
+++ b/drivers/clk/Kconfig
|
||||
@@ -96,6 +96,12 @@ config COMMON_CLK_RP1
|
||||
help
|
||||
Enable common clock framework support for Raspberry Pi RP1
|
||||
|
||||
+config COMMON_CLK_RP1_SDIO
|
||||
+ tristate "Clock driver for the RP1 SDIO interfaces"
|
||||
+ depends on MFD_RP1
|
||||
+ help
|
||||
+ SDIO clock driver for the RP1 support chip
|
||||
+
|
||||
config COMMON_CLK_HI655X
|
||||
tristate "Clock driver for Hi655x" if EXPERT
|
||||
depends on (MFD_HI655X_PMIC || COMPILE_TEST)
|
||||
--- a/drivers/clk/Makefile
|
||||
+++ b/drivers/clk/Makefile
|
||||
@@ -59,6 +59,7 @@ obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm
|
||||
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
|
||||
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
|
||||
obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o
|
||||
+obj-$(CONFIG_COMMON_CLK_RP1_SDIO) += clk-rp1-sdio.o
|
||||
obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o
|
||||
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
|
||||
obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/clk/clk-rp1-sdio.c
|
||||
@@ -0,0 +1,600 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * SDIO clock driver for RP1
|
||||
+ *
|
||||
+ * Copyright (C) 2023 Raspberry Pi Ltd.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+// Register : MODE
|
||||
+#define MODE 0x00000000
|
||||
+#define MODE_BITS 0x70030000
|
||||
+#define MODE_RESET 0x00000000
|
||||
+// Field : MODE_STEPS_PER_CYCLE
|
||||
+#define MODE_STEPS_PER_CYCLE_RESET 0x0
|
||||
+#define MODE_STEPS_PER_CYCLE_BITS 0x70000000
|
||||
+#define MODE_STEPS_PER_CYCLE_MSB 30
|
||||
+#define MODE_STEPS_PER_CYCLE_LSB 28
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_20 0x0
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_10 0x1
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_16 0x2
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_8 0x3
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_12 0x4
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_6 0x5
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_5 0x6
|
||||
+#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_4 0x7
|
||||
+// Field : MODE_SRC_SEL
|
||||
+#define MODE_SRC_SEL_RESET 0x0
|
||||
+#define MODE_SRC_SEL_BITS 0x00030000
|
||||
+#define MODE_SRC_SEL_MSB 17
|
||||
+#define MODE_SRC_SEL_LSB 16
|
||||
+#define MODE_SRC_SEL_VALUE_STOP 0x0
|
||||
+#define MODE_SRC_SEL_VALUE_CLK_ALT_SRC 0x1
|
||||
+#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO 0x2
|
||||
+#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO_AGAIN 0x3
|
||||
+// Register : FROMIP
|
||||
+#define FROMIP 0x00000004
|
||||
+#define FROMIP_BITS 0x0f9713ff
|
||||
+#define FROMIP_RESET 0x00000000
|
||||
+// Field : FROMIP_TUNING_CCLK_SEL
|
||||
+#define FROMIP_TUNING_CCLK_SEL_RESET 0x0
|
||||
+#define FROMIP_TUNING_CCLK_SEL_BITS 0x0f000000
|
||||
+#define FROMIP_TUNING_CCLK_SEL_MSB 27
|
||||
+#define FROMIP_TUNING_CCLK_SEL_LSB 24
|
||||
+// Field : FROMIP_TUNING_CCLK_UPDATE
|
||||
+#define FROMIP_TUNING_CCLK_UPDATE_RESET 0x0
|
||||
+#define FROMIP_TUNING_CCLK_UPDATE_BITS 0x00800000
|
||||
+#define FROMIP_TUNING_CCLK_UPDATE_MSB 23
|
||||
+#define FROMIP_TUNING_CCLK_UPDATE_LSB 23
|
||||
+// Field : FROMIP_SAMPLE_CCLK_SEL
|
||||
+#define FROMIP_SAMPLE_CCLK_SEL_RESET 0x0
|
||||
+#define FROMIP_SAMPLE_CCLK_SEL_BITS 0x00100000
|
||||
+#define FROMIP_SAMPLE_CCLK_SEL_MSB 20
|
||||
+#define FROMIP_SAMPLE_CCLK_SEL_LSB 20
|
||||
+// Field : FROMIP_CLK2CARD_ON
|
||||
+#define FROMIP_CLK2CARD_ON_RESET 0x0
|
||||
+#define FROMIP_CLK2CARD_ON_BITS 0x00040000
|
||||
+#define FROMIP_CLK2CARD_ON_MSB 18
|
||||
+#define FROMIP_CLK2CARD_ON_LSB 18
|
||||
+// Field : FROMIP_CARD_CLK_STABLE
|
||||
+#define FROMIP_CARD_CLK_STABLE_RESET 0x0
|
||||
+#define FROMIP_CARD_CLK_STABLE_BITS 0x00020000
|
||||
+#define FROMIP_CARD_CLK_STABLE_MSB 17
|
||||
+#define FROMIP_CARD_CLK_STABLE_LSB 17
|
||||
+// Field : FROMIP_CARD_CLK_EN
|
||||
+#define FROMIP_CARD_CLK_EN_RESET 0x0
|
||||
+#define FROMIP_CARD_CLK_EN_BITS 0x00010000
|
||||
+#define FROMIP_CARD_CLK_EN_MSB 16
|
||||
+#define FROMIP_CARD_CLK_EN_LSB 16
|
||||
+// Field : FROMIP_CLK_GEN_SEL
|
||||
+#define FROMIP_CLK_GEN_SEL_RESET 0x0
|
||||
+#define FROMIP_CLK_GEN_SEL_BITS 0x00001000
|
||||
+#define FROMIP_CLK_GEN_SEL_MSB 12
|
||||
+#define FROMIP_CLK_GEN_SEL_LSB 12
|
||||
+// Field : FROMIP_FREQ_SEL
|
||||
+#define FROMIP_FREQ_SEL_RESET 0x000
|
||||
+#define FROMIP_FREQ_SEL_BITS 0x000003ff
|
||||
+#define FROMIP_FREQ_SEL_MSB 9
|
||||
+#define FROMIP_FREQ_SEL_LSB 0
|
||||
+// Register : LOCAL
|
||||
+#define LOCAL 0x00000008
|
||||
+#define LOCAL_BITS 0x1f9713ff
|
||||
+#define LOCAL_RESET 0x00000000
|
||||
+// Field : LOCAL_TUNING_CCLK_SEL
|
||||
+#define LOCAL_TUNING_CCLK_SEL_RESET 0x00
|
||||
+#define LOCAL_TUNING_CCLK_SEL_BITS 0x1f000000
|
||||
+#define LOCAL_TUNING_CCLK_SEL_MSB 28
|
||||
+#define LOCAL_TUNING_CCLK_SEL_LSB 24
|
||||
+// Field : LOCAL_TUNING_CCLK_UPDATE
|
||||
+#define LOCAL_TUNING_CCLK_UPDATE_RESET 0x0
|
||||
+#define LOCAL_TUNING_CCLK_UPDATE_BITS 0x00800000
|
||||
+#define LOCAL_TUNING_CCLK_UPDATE_MSB 23
|
||||
+#define LOCAL_TUNING_CCLK_UPDATE_LSB 23
|
||||
+// Field : LOCAL_SAMPLE_CCLK_SEL
|
||||
+#define LOCAL_SAMPLE_CCLK_SEL_RESET 0x0
|
||||
+#define LOCAL_SAMPLE_CCLK_SEL_BITS 0x00100000
|
||||
+#define LOCAL_SAMPLE_CCLK_SEL_MSB 20
|
||||
+#define LOCAL_SAMPLE_CCLK_SEL_LSB 20
|
||||
+// Field : LOCAL_CLK2CARD_ON
|
||||
+#define LOCAL_CLK2CARD_ON_RESET 0x0
|
||||
+#define LOCAL_CLK2CARD_ON_BITS 0x00040000
|
||||
+#define LOCAL_CLK2CARD_ON_MSB 18
|
||||
+#define LOCAL_CLK2CARD_ON_LSB 18
|
||||
+// Field : LOCAL_CARD_CLK_STABLE
|
||||
+#define LOCAL_CARD_CLK_STABLE_RESET 0x0
|
||||
+#define LOCAL_CARD_CLK_STABLE_BITS 0x00020000
|
||||
+#define LOCAL_CARD_CLK_STABLE_MSB 17
|
||||
+#define LOCAL_CARD_CLK_STABLE_LSB 17
|
||||
+// Field : LOCAL_CARD_CLK_EN
|
||||
+#define LOCAL_CARD_CLK_EN_RESET 0x0
|
||||
+#define LOCAL_CARD_CLK_EN_BITS 0x00010000
|
||||
+#define LOCAL_CARD_CLK_EN_MSB 16
|
||||
+#define LOCAL_CARD_CLK_EN_LSB 16
|
||||
+// Field : LOCAL_CLK_GEN_SEL
|
||||
+#define LOCAL_CLK_GEN_SEL_RESET 0x0
|
||||
+#define LOCAL_CLK_GEN_SEL_BITS 0x00001000
|
||||
+#define LOCAL_CLK_GEN_SEL_MSB 12
|
||||
+#define LOCAL_CLK_GEN_SEL_LSB 12
|
||||
+#define LOCAL_CLK_GEN_SEL_VALUE_PROGCLOCKMODE 0x0
|
||||
+#define LOCAL_CLK_GEN_SEL_VALUE_DIVCLOCKMODE 0x1
|
||||
+// Field : LOCAL_FREQ_SEL
|
||||
+#define LOCAL_FREQ_SEL_RESET 0x000
|
||||
+#define LOCAL_FREQ_SEL_BITS 0x000003ff
|
||||
+#define LOCAL_FREQ_SEL_MSB 9
|
||||
+#define LOCAL_FREQ_SEL_LSB 0
|
||||
+// Register : USE_LOCAL
|
||||
+#define USE_LOCAL 0x0000000c
|
||||
+#define USE_LOCAL_BITS 0x01951001
|
||||
+#define USE_LOCAL_RESET 0x00000000
|
||||
+// Field : USE_LOCAL_TUNING_CCLK_SEL
|
||||
+#define USE_LOCAL_TUNING_CCLK_SEL_RESET 0x0
|
||||
+#define USE_LOCAL_TUNING_CCLK_SEL_BITS 0x01000000
|
||||
+#define USE_LOCAL_TUNING_CCLK_SEL_MSB 24
|
||||
+#define USE_LOCAL_TUNING_CCLK_SEL_LSB 24
|
||||
+// Field : USE_LOCAL_TUNING_CCLK_UPDATE
|
||||
+#define USE_LOCAL_TUNING_CCLK_UPDATE_RESET 0x0
|
||||
+#define USE_LOCAL_TUNING_CCLK_UPDATE_BITS 0x00800000
|
||||
+#define USE_LOCAL_TUNING_CCLK_UPDATE_MSB 23
|
||||
+#define USE_LOCAL_TUNING_CCLK_UPDATE_LSB 23
|
||||
+// Field : USE_LOCAL_SAMPLE_CCLK_SEL
|
||||
+#define USE_LOCAL_SAMPLE_CCLK_SEL_RESET 0x0
|
||||
+#define USE_LOCAL_SAMPLE_CCLK_SEL_BITS 0x00100000
|
||||
+#define USE_LOCAL_SAMPLE_CCLK_SEL_MSB 20
|
||||
+#define USE_LOCAL_SAMPLE_CCLK_SEL_LSB 20
|
||||
+// Field : USE_LOCAL_CLK2CARD_ON
|
||||
+#define USE_LOCAL_CLK2CARD_ON_RESET 0x0
|
||||
+#define USE_LOCAL_CLK2CARD_ON_BITS 0x00040000
|
||||
+#define USE_LOCAL_CLK2CARD_ON_MSB 18
|
||||
+#define USE_LOCAL_CLK2CARD_ON_LSB 18
|
||||
+// Field : USE_LOCAL_CARD_CLK_EN
|
||||
+#define USE_LOCAL_CARD_CLK_EN_RESET 0x0
|
||||
+#define USE_LOCAL_CARD_CLK_EN_BITS 0x00010000
|
||||
+#define USE_LOCAL_CARD_CLK_EN_MSB 16
|
||||
+#define USE_LOCAL_CARD_CLK_EN_LSB 16
|
||||
+// Field : USE_LOCAL_CLK_GEN_SEL
|
||||
+#define USE_LOCAL_CLK_GEN_SEL_RESET 0x0
|
||||
+#define USE_LOCAL_CLK_GEN_SEL_BITS 0x00001000
|
||||
+#define USE_LOCAL_CLK_GEN_SEL_MSB 12
|
||||
+#define USE_LOCAL_CLK_GEN_SEL_LSB 12
|
||||
+// Field : USE_LOCAL_FREQ_SEL
|
||||
+#define USE_LOCAL_FREQ_SEL_RESET 0x0
|
||||
+#define USE_LOCAL_FREQ_SEL_BITS 0x00000001
|
||||
+#define USE_LOCAL_FREQ_SEL_MSB 0
|
||||
+#define USE_LOCAL_FREQ_SEL_LSB 0
|
||||
+// Register : SD_DELAY
|
||||
+#define SD_DELAY 0x00000010
|
||||
+#define SD_DELAY_BITS 0x0000001f
|
||||
+#define SD_DELAY_RESET 0x00000000
|
||||
+// Field : SD_DELAY_STEPS
|
||||
+#define SD_DELAY_STEPS_RESET 0x00
|
||||
+#define SD_DELAY_STEPS_BITS 0x0000001f
|
||||
+#define SD_DELAY_STEPS_MSB 4
|
||||
+#define SD_DELAY_STEPS_LSB 0
|
||||
+// Register : RX_DELAY
|
||||
+#define RX_DELAY 0x00000014
|
||||
+#define RX_DELAY_BITS 0x19f3331f
|
||||
+#define RX_DELAY_RESET 0x00000000
|
||||
+// Field : RX_DELAY_BYPASS
|
||||
+#define RX_DELAY_BYPASS_RESET 0x0
|
||||
+#define RX_DELAY_BYPASS_BITS 0x10000000
|
||||
+#define RX_DELAY_BYPASS_MSB 28
|
||||
+#define RX_DELAY_BYPASS_LSB 28
|
||||
+// Field : RX_DELAY_FAIL_ACTUAL
|
||||
+#define RX_DELAY_FAIL_ACTUAL_RESET 0x0
|
||||
+#define RX_DELAY_FAIL_ACTUAL_BITS 0x08000000
|
||||
+#define RX_DELAY_FAIL_ACTUAL_MSB 27
|
||||
+#define RX_DELAY_FAIL_ACTUAL_LSB 27
|
||||
+// Field : RX_DELAY_ACTUAL
|
||||
+#define RX_DELAY_ACTUAL_RESET 0x00
|
||||
+#define RX_DELAY_ACTUAL_BITS 0x01f00000
|
||||
+#define RX_DELAY_ACTUAL_MSB 24
|
||||
+#define RX_DELAY_ACTUAL_LSB 20
|
||||
+// Field : RX_DELAY_OFFSET
|
||||
+#define RX_DELAY_OFFSET_RESET 0x0
|
||||
+#define RX_DELAY_OFFSET_BITS 0x00030000
|
||||
+#define RX_DELAY_OFFSET_MSB 17
|
||||
+#define RX_DELAY_OFFSET_LSB 16
|
||||
+// Field : RX_DELAY_OVERFLOW
|
||||
+#define RX_DELAY_OVERFLOW_RESET 0x0
|
||||
+#define RX_DELAY_OVERFLOW_BITS 0x00003000
|
||||
+#define RX_DELAY_OVERFLOW_MSB 13
|
||||
+#define RX_DELAY_OVERFLOW_LSB 12
|
||||
+#define RX_DELAY_OVERFLOW_VALUE_ALLOW 0x0
|
||||
+#define RX_DELAY_OVERFLOW_VALUE_CLAMP 0x1
|
||||
+#define RX_DELAY_OVERFLOW_VALUE_FAIL 0x2
|
||||
+// Field : RX_DELAY_MAP
|
||||
+#define RX_DELAY_MAP_RESET 0x0
|
||||
+#define RX_DELAY_MAP_BITS 0x00000300
|
||||
+#define RX_DELAY_MAP_MSB 9
|
||||
+#define RX_DELAY_MAP_LSB 8
|
||||
+#define RX_DELAY_MAP_VALUE_DIRECT 0x0
|
||||
+#define RX_DELAY_MAP_VALUE 0x1
|
||||
+#define RX_DELAY_MAP_VALUE_STRETCH 0x2
|
||||
+// Field : RX_DELAY_FIXED
|
||||
+#define RX_DELAY_FIXED_RESET 0x00
|
||||
+#define RX_DELAY_FIXED_BITS 0x0000001f
|
||||
+#define RX_DELAY_FIXED_MSB 4
|
||||
+#define RX_DELAY_FIXED_LSB 0
|
||||
+// Register : NDIV
|
||||
+#define NDIV 0x00000018
|
||||
+#define NDIV_BITS 0x1fff0000
|
||||
+#define NDIV_RESET 0x00110000
|
||||
+// Field : NDIV_DIVB
|
||||
+#define NDIV_DIVB_RESET 0x001
|
||||
+#define NDIV_DIVB_BITS 0x1ff00000
|
||||
+#define NDIV_DIVB_MSB 28
|
||||
+#define NDIV_DIVB_LSB 20
|
||||
+// Field : NDIV_DIVA
|
||||
+#define NDIV_DIVA_RESET 0x1
|
||||
+#define NDIV_DIVA_BITS 0x000f0000
|
||||
+#define NDIV_DIVA_MSB 19
|
||||
+#define NDIV_DIVA_LSB 16
|
||||
+// Register : CS
|
||||
+#define CS 0x0000001c
|
||||
+#define CS_BITS 0x00111101
|
||||
+#define CS_RESET 0x00000001
|
||||
+// Field : CS_RX_DEL_UPDATED
|
||||
+#define CS_RX_DEL_UPDATED_RESET 0x0
|
||||
+#define CS_RX_DEL_UPDATED_BITS 0x00100000
|
||||
+#define CS_RX_DEL_UPDATED_MSB 20
|
||||
+#define CS_RX_DEL_UPDATED_LSB 20
|
||||
+// Field : CS_RX_CLK_RUNNING
|
||||
+#define CS_RX_CLK_RUNNING_RESET 0x0
|
||||
+#define CS_RX_CLK_RUNNING_BITS 0x00010000
|
||||
+#define CS_RX_CLK_RUNNING_MSB 16
|
||||
+#define CS_RX_CLK_RUNNING_LSB 16
|
||||
+// Field : CS_SD_CLK_RUNNING
|
||||
+#define CS_SD_CLK_RUNNING_RESET 0x0
|
||||
+#define CS_SD_CLK_RUNNING_BITS 0x00001000
|
||||
+#define CS_SD_CLK_RUNNING_MSB 12
|
||||
+#define CS_SD_CLK_RUNNING_LSB 12
|
||||
+// Field : CS_TX_CLK_RUNNING
|
||||
+#define CS_TX_CLK_RUNNING_RESET 0x0
|
||||
+#define CS_TX_CLK_RUNNING_BITS 0x00000100
|
||||
+#define CS_TX_CLK_RUNNING_MSB 8
|
||||
+#define CS_TX_CLK_RUNNING_LSB 8
|
||||
+// Field : CS_RESET
|
||||
+#define CS_RESET_RESET 0x1
|
||||
+#define CS_RESET_BITS 0x00000001
|
||||
+#define CS_RESET_MSB 0
|
||||
+#define CS_RESET_LSB 0
|
||||
+
|
||||
+#define FPGA_SRC_RATE 400000000
|
||||
+
|
||||
+/* Base number of steps to delay in relation to tx clk.
|
||||
+ * The relationship of the 3 clocks are as follows:
|
||||
+ * tx_clk: This clock is provided to the controller. Data is sent out
|
||||
+ * to the pads using this clock.
|
||||
+ * sd_clk: This clock is sent out to the card.
|
||||
+ * rx_clk: This clock is used to sample the data coming back from the card.
|
||||
+ * This may need to be several steps ahead of the tx_clk. The default rx delay
|
||||
+ * is used as a base delay, and can be further adjusted by the sd host
|
||||
+ * controller during the tuning process if using a DDR50 or faster SD card
|
||||
+ */
|
||||
+/*
|
||||
+ * PRJY-1813 - the default SD clock delay needs to be set to ~60% of the total
|
||||
+ * number of steps to meet tISU (>6ns) and tIH (>2ns) in high-speed mode.
|
||||
+ * On FPGA this means delay SDCLK by 5, and sample RX with a delay of 6.
|
||||
+ */
|
||||
+#define DEFAULT_RX_DELAY 6
|
||||
+#define DEFAULT_SD_DELAY 5
|
||||
+
|
||||
+struct rp1_sdio_clkgen {
|
||||
+ struct device *dev;
|
||||
+
|
||||
+ /* Source clock. Either PLL VCO or fixed freq on FPGA */
|
||||
+ struct clk *src_clk;
|
||||
+ /* Desired base frequency. Max freq card can go */
|
||||
+ struct clk *base_clk;
|
||||
+
|
||||
+ struct clk_hw hw;
|
||||
+ void __iomem *regs;
|
||||
+
|
||||
+ /* Starting value of local register before changing freq */
|
||||
+ u32 local_base;
|
||||
+};
|
||||
+
|
||||
+static inline void clkgen_write(struct rp1_sdio_clkgen *clkgen, u32 reg, u32 val)
|
||||
+{
|
||||
+ dev_dbg(clkgen->dev, "%s: write reg 0x%x: 0x%x\n", __func__, reg, val);
|
||||
+ writel(val, clkgen->regs + reg);
|
||||
+}
|
||||
+
|
||||
+static inline u32 clkgen_read(struct rp1_sdio_clkgen *clkgen, u32 reg)
|
||||
+{
|
||||
+ u32 val = readl(clkgen->regs + reg);
|
||||
+
|
||||
+ dev_dbg(clkgen->dev, "%s: read reg 0x%x: 0x%x\n", __func__, reg, val);
|
||||
+ return val;
|
||||
+}
|
||||
+
|
||||
+static int get_steps(unsigned int steps)
|
||||
+{
|
||||
+ int ret = -1;
|
||||
+
|
||||
+ if (steps == 4)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_4;
|
||||
+ else if (steps == 5)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_5;
|
||||
+ else if (steps == 6)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_6;
|
||||
+ else if (steps == 8)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_8;
|
||||
+ else if (steps == 10)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_10;
|
||||
+ else if (steps == 12)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_12;
|
||||
+ else if (steps == 16)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_16;
|
||||
+ else if (steps == 20)
|
||||
+ ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_20;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rp1_sdio_clk_init(struct rp1_sdio_clkgen *clkgen)
|
||||
+{
|
||||
+ unsigned long src_rate = clk_get_rate(clkgen->src_clk);
|
||||
+ unsigned long base_rate = clk_get_rate(clkgen->base_clk);
|
||||
+ unsigned int steps = src_rate / base_rate;
|
||||
+ u32 reg = 0;
|
||||
+ int steps_value = 0;
|
||||
+
|
||||
+ dev_dbg(clkgen->dev, "init: src_rate %lu, base_rate %lu, steps %d\n",
|
||||
+ src_rate, base_rate, steps);
|
||||
+
|
||||
+ /* Assert reset while we set up clkgen */
|
||||
+ clkgen_write(clkgen, CS, CS_RESET_BITS);
|
||||
+
|
||||
+ /* Pick clock source */
|
||||
+ if (src_rate == FPGA_SRC_RATE) {
|
||||
+ /* Using ALT SRC */
|
||||
+ reg |= MODE_SRC_SEL_VALUE_CLK_ALT_SRC << MODE_SRC_SEL_LSB;
|
||||
+ } else {
|
||||
+ /* Assume we are using PLL SYS VCO */
|
||||
+ reg |= MODE_SRC_SEL_VALUE_PLL_SYS_VCO << MODE_SRC_SEL_LSB;
|
||||
+ }
|
||||
+
|
||||
+ /* How many delay steps are available in one cycle for this source */
|
||||
+ steps_value = get_steps(steps);
|
||||
+ if (steps_value < 0) {
|
||||
+ dev_err(clkgen->dev, "Invalid step value: %d\n", steps);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ reg |= steps_value << MODE_STEPS_PER_CYCLE_LSB;
|
||||
+
|
||||
+ /* Mode register is done now*/
|
||||
+ clkgen_write(clkgen, MODE, reg);
|
||||
+
|
||||
+ /* Now set delay mode */
|
||||
+ /* Clamp value if out of range rx delay is used */
|
||||
+ reg = RX_DELAY_OVERFLOW_VALUE_CLAMP << RX_DELAY_OVERFLOW_LSB;
|
||||
+ /* SD tuning bus goes from 0x0 to 0xf but we don't necessarily have that
|
||||
+ * many steps available depending on the source so map 0x0 -> 0xf to one
|
||||
+ * cycle of rx delay
|
||||
+ */
|
||||
+ reg |= RX_DELAY_MAP_VALUE_STRETCH << RX_DELAY_MAP_LSB;
|
||||
+
|
||||
+ /* Default RX delay */
|
||||
+ dev_dbg(clkgen->dev, "default rx delay %d\n", DEFAULT_RX_DELAY);
|
||||
+ reg |= (DEFAULT_RX_DELAY & RX_DELAY_FIXED_BITS) << RX_DELAY_FIXED_LSB;
|
||||
+ clkgen_write(clkgen, RX_DELAY, reg);
|
||||
+
|
||||
+ /* Default SD delay */
|
||||
+ dev_dbg(clkgen->dev, "default sd delay %d\n", DEFAULT_SD_DELAY);
|
||||
+ reg = (DEFAULT_SD_DELAY & SD_DELAY_STEPS_BITS) << SD_DELAY_STEPS_LSB;
|
||||
+ clkgen_write(clkgen, SD_DELAY, reg);
|
||||
+
|
||||
+ /* We select freq, we turn on tx clock, we turn on sd clk,
|
||||
+ * we pick clock generator mode
|
||||
+ */
|
||||
+ reg = USE_LOCAL_FREQ_SEL_BITS | USE_LOCAL_CARD_CLK_EN_BITS |
|
||||
+ USE_LOCAL_CLK2CARD_ON_BITS | USE_LOCAL_CLK_GEN_SEL_BITS;
|
||||
+ clkgen_write(clkgen, USE_LOCAL, reg);
|
||||
+
|
||||
+ /* Deassert reset. Reset bit is only writable bit of CS
|
||||
+ * reg so fine to write a 0.
|
||||
+ */
|
||||
+ clkgen_write(clkgen, CS, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#define RUNNING \
|
||||
+ (CS_TX_CLK_RUNNING_BITS | CS_RX_CLK_RUNNING_BITS | \
|
||||
+ CS_SD_CLK_RUNNING_BITS)
|
||||
+static int rp1_sdio_clk_is_prepared(struct clk_hw *hw)
|
||||
+{
|
||||
+ struct rp1_sdio_clkgen *clkgen =
|
||||
+ container_of(hw, struct rp1_sdio_clkgen, hw);
|
||||
+ u32 status;
|
||||
+
|
||||
+ dev_dbg(clkgen->dev, "is_prepared\n");
|
||||
+ status = clkgen_read(clkgen, CS);
|
||||
+ return ((status & RUNNING) == RUNNING);
|
||||
+}
|
||||
+
|
||||
+/* Can define an additional divider if an sd card isn't working at full speed */
|
||||
+/* #define SLOWDOWN 3 */
|
||||
+
|
||||
+static unsigned long rp1_sdio_clk_get_rate(struct clk_hw *hw,
|
||||
+ unsigned long parent_rate)
|
||||
+{
|
||||
+ /* Get the current rate */
|
||||
+ struct rp1_sdio_clkgen *clkgen =
|
||||
+ container_of(hw, struct rp1_sdio_clkgen, hw);
|
||||
+ unsigned long actual_rate = 0;
|
||||
+ u32 ndiv_diva;
|
||||
+ u32 ndiv_divb;
|
||||
+ u32 tmp;
|
||||
+ u32 div;
|
||||
+
|
||||
+ tmp = clkgen_read(clkgen, LOCAL);
|
||||
+ if ((tmp & LOCAL_CLK2CARD_ON_BITS) == 0) {
|
||||
+ dev_dbg(clkgen->dev, "get_rate 0\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ tmp = clkgen_read(clkgen, NDIV);
|
||||
+ ndiv_diva = (tmp & NDIV_DIVA_BITS) >> NDIV_DIVA_LSB;
|
||||
+ ndiv_divb = (tmp & NDIV_DIVB_BITS) >> NDIV_DIVB_LSB;
|
||||
+ div = ndiv_diva * ndiv_divb;
|
||||
+ actual_rate = (clk_get_rate(clkgen->base_clk) / div);
|
||||
+
|
||||
+#ifdef SLOWDOWN
|
||||
+ actual_rate *= SLOWDOWN;
|
||||
+#endif
|
||||
+
|
||||
+ dev_dbg(clkgen->dev, "get_rate. ndiv_diva %d, ndiv_divb %d = %lu\n",
|
||||
+ ndiv_diva, ndiv_divb, actual_rate);
|
||||
+
|
||||
+ return actual_rate;
|
||||
+}
|
||||
+
|
||||
+static int rp1_sdio_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
+ unsigned long parent_rate)
|
||||
+{
|
||||
+ struct rp1_sdio_clkgen *clkgen =
|
||||
+ container_of(hw, struct rp1_sdio_clkgen, hw);
|
||||
+ u32 div;
|
||||
+ u32 reg;
|
||||
+
|
||||
+ dev_dbg(clkgen->dev, "set_rate %lu\n", rate);
|
||||
+
|
||||
+ if (rate == 0) {
|
||||
+ /* Keep tx clock running */
|
||||
+ clkgen_write(clkgen, LOCAL, LOCAL_CARD_CLK_EN_BITS);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+#ifdef SLOWDOWN
|
||||
+ rate /= SLOWDOWN;
|
||||
+#endif
|
||||
+
|
||||
+ div = (clk_get_rate(clkgen->base_clk) / rate) - 1;
|
||||
+ reg = LOCAL_CLK_GEN_SEL_BITS | LOCAL_CARD_CLK_EN_BITS |
|
||||
+ LOCAL_CLK2CARD_ON_BITS | (div << LOCAL_FREQ_SEL_LSB);
|
||||
+ clkgen_write(clkgen, LOCAL, reg);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#define MAX_NDIV (256 * 8)
|
||||
+static int rp1_sdio_clk_determine_rate(struct clk_hw *hw,
|
||||
+ struct clk_rate_request *req)
|
||||
+{
|
||||
+ unsigned long rate;
|
||||
+ struct rp1_sdio_clkgen *clkgen =
|
||||
+ container_of(hw, struct rp1_sdio_clkgen, hw);
|
||||
+ unsigned long base_rate = clk_get_rate(clkgen->base_clk);
|
||||
+ u32 div;
|
||||
+
|
||||
+ /* What is the actual rate I can get if I request xyz */
|
||||
+ if (req->rate) {
|
||||
+ div = min((u32)(base_rate / req->rate), (u32)MAX_NDIV);
|
||||
+ rate = base_rate / div;
|
||||
+ req->rate = rate;
|
||||
+ dev_dbg(clkgen->dev, "determine_rate %lu: %lu / %d = %lu\n",
|
||||
+ req->rate, base_rate, div, rate);
|
||||
+ } else {
|
||||
+ rate = 0;
|
||||
+ dev_dbg(clkgen->dev, "determine_rate %lu: %lu\n", req->rate,
|
||||
+ rate);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct clk_ops rp1_sdio_clk_ops = {
|
||||
+ .is_prepared = rp1_sdio_clk_is_prepared,
|
||||
+ .recalc_rate = rp1_sdio_clk_get_rate,
|
||||
+ .set_rate = rp1_sdio_clk_set_rate,
|
||||
+ .determine_rate = rp1_sdio_clk_determine_rate,
|
||||
+};
|
||||
+
|
||||
+static int rp1_sdio_clk_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *node = pdev->dev.of_node;
|
||||
+ struct rp1_sdio_clkgen *clkgen;
|
||||
+ void __iomem *regs;
|
||||
+ struct clk_init_data init = {};
|
||||
+ int ret;
|
||||
+
|
||||
+ clkgen = devm_kzalloc(&pdev->dev, sizeof(*clkgen), GFP_KERNEL);
|
||||
+ if (!clkgen)
|
||||
+ return -ENOMEM;
|
||||
+ platform_set_drvdata(pdev, clkgen);
|
||||
+
|
||||
+ clkgen->dev = &pdev->dev;
|
||||
+
|
||||
+ /* Source freq */
|
||||
+ clkgen->src_clk = devm_clk_get(&pdev->dev, "src");
|
||||
+ if (IS_ERR(clkgen->src_clk)) {
|
||||
+ int err = PTR_ERR(clkgen->src_clk);
|
||||
+
|
||||
+ dev_err(&pdev->dev, "failed to get src clk: %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ /* Desired maximum output freq (i.e. base freq) */
|
||||
+ clkgen->base_clk = devm_clk_get(&pdev->dev, "base");
|
||||
+ if (IS_ERR(clkgen->base_clk)) {
|
||||
+ int err = PTR_ERR(clkgen->base_clk);
|
||||
+
|
||||
+ dev_err(&pdev->dev, "failed to get base clk: %d\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(regs))
|
||||
+ return PTR_ERR(regs);
|
||||
+
|
||||
+ init.name = node->name;
|
||||
+ init.ops = &rp1_sdio_clk_ops;
|
||||
+ init.flags = CLK_GET_RATE_NOCACHE;
|
||||
+
|
||||
+ clkgen->hw.init = &init;
|
||||
+ clkgen->regs = regs;
|
||||
+
|
||||
+ dev_info(&pdev->dev, "loaded %s\n", init.name);
|
||||
+
|
||||
+ ret = devm_clk_hw_register(&pdev->dev, &clkgen->hw);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clkgen->hw);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = rp1_sdio_clk_init(clkgen);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rp1_sdio_clk_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id rp1_sdio_clk_dt_ids[] = {
|
||||
+ { .compatible = "raspberrypi,rp1-sdio-clk", },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rp1_sdio_clk_dt_ids);
|
||||
+
|
||||
+static struct platform_driver rp1_sdio_clk_driver = {
|
||||
+ .probe = rp1_sdio_clk_probe,
|
||||
+ .remove = rp1_sdio_clk_remove,
|
||||
+ .driver = {
|
||||
+ .name = "rp1-sdio-clk",
|
||||
+ .of_match_table = rp1_sdio_clk_dt_ids,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(rp1_sdio_clk_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Liam Fraser <liam@raspberrypi.com>");
|
||||
+MODULE_DESCRIPTION("RP1 SDIO clock driver");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,76 @@
|
||||
From 50adadfaf324ed5cbb59ce2b85eda59de4e3801a Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 4 Dec 2020 15:20:36 +0000
|
||||
Subject: [PATCH] i2c: designware: Add SMBUS quick command support
|
||||
|
||||
The SMBUS emulation code turns an SMBUS quick command into a zero-
|
||||
length read. This controller can't do zero length accesses, but it
|
||||
can do quick commands, so reverse the emulation. The alternative
|
||||
would be to properly implement the SMBUS support but that is a lot
|
||||
more work, and unnecessary just to get i2cdetect working.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/i2c/busses/i2c-designware-core.h | 2 ++
|
||||
drivers/i2c/busses/i2c-designware-master.c | 17 +++++++++++++++--
|
||||
2 files changed, 17 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/i2c/busses/i2c-designware-core.h
|
||||
+++ b/drivers/i2c/busses/i2c-designware-core.h
|
||||
@@ -117,7 +117,9 @@
|
||||
|
||||
#define DW_IC_ERR_TX_ABRT 0x1
|
||||
|
||||
+#define DW_IC_TAR_SPECIAL BIT(11)
|
||||
#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
|
||||
+#define DW_IC_TAR_SMBUS_QUICK_CMD BIT(16)
|
||||
|
||||
#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
|
||||
#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
|
||||
--- a/drivers/i2c/busses/i2c-designware-master.c
|
||||
+++ b/drivers/i2c/busses/i2c-designware-master.c
|
||||
@@ -228,6 +228,10 @@ static void i2c_dw_xfer_init(struct dw_i
|
||||
ic_tar = DW_IC_TAR_10BITADDR_MASTER;
|
||||
}
|
||||
|
||||
+ /* Convert a zero-length read into an SMBUS quick command */
|
||||
+ if (!msgs[dev->msg_write_idx].len)
|
||||
+ ic_tar = DW_IC_TAR_SPECIAL | DW_IC_TAR_SMBUS_QUICK_CMD;
|
||||
+
|
||||
regmap_update_bits(dev->map, DW_IC_CON, DW_IC_CON_10BITADDR_MASTER,
|
||||
ic_con);
|
||||
|
||||
@@ -409,6 +413,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
|
||||
regmap_read(dev->map, DW_IC_RXFLR, &flr);
|
||||
rx_limit = dev->rx_fifo_depth - flr;
|
||||
|
||||
+ /* Handle SMBUS quick commands */
|
||||
+ if (!buf_len) {
|
||||
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD)
|
||||
+ regmap_write(dev->map, DW_IC_DATA_CMD, 0x300);
|
||||
+ else
|
||||
+ regmap_write(dev->map, DW_IC_DATA_CMD, 0x200);
|
||||
+ }
|
||||
+
|
||||
while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
|
||||
u32 cmd = 0;
|
||||
|
||||
@@ -673,7 +685,7 @@ static const struct i2c_algorithm i2c_dw
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks i2c_dw_quirks = {
|
||||
- .flags = I2C_AQ_NO_ZERO_LEN,
|
||||
+ .flags = 0,
|
||||
};
|
||||
|
||||
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
|
||||
@@ -813,7 +825,8 @@ void i2c_dw_configure_master(struct dw_i
|
||||
{
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
|
||||
- dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
+ dev->functionality = I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_QUICK |
|
||||
+ DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
|
||||
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
|
||||
DW_IC_CON_RESTART_EN;
|
@ -0,0 +1,355 @@
|
||||
From 0a1cd70189daec3baf4b4a233dd8e25ffbb9d512 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 28 Apr 2021 17:46:01 +0100
|
||||
Subject: [PATCH] dmaengine: dw-axi-dmac: Fixes for RP1
|
||||
|
||||
Don't assume that DMA addresses of devices are the same as their
|
||||
physical addresses - convert correctly.
|
||||
|
||||
The CFG2 register layout is used when there are more than 8 channels,
|
||||
but also when configured for more than 16 target peripheral devices
|
||||
because the index of the handshake signal has to be made wider.
|
||||
|
||||
Reset the DMAC on probe
|
||||
|
||||
The driver goes to the trouble of tracking when transfers have been
|
||||
paused, but then doesn't report that state when queried.
|
||||
|
||||
Not having APB registers is not an error - for most use cases it's
|
||||
not even of interest, it's expected. Demote the message to debug level,
|
||||
which is disabled by default.
|
||||
|
||||
Each channel has a descriptor pool, which is shared between transfers.
|
||||
It is unsafe to treat the total number of descriptors allocated from a
|
||||
pool as the number allocated to a specific transfer; doing so leads
|
||||
to releasing buffers that shouldn't be released and walking off the
|
||||
ends of descriptor lists. Instead, give each transfer descriptor its
|
||||
own count.
|
||||
|
||||
Support partial transfers:
|
||||
Some use cases involve streaming from a device where the transfer only
|
||||
proceeds when the device's FIFO occupancy exceeds a certain threshold.
|
||||
In such cases (e.g. when pulling data from a UART) it is important to
|
||||
know how much data has been transferred so far, in order that remaining
|
||||
bytes can be read from the FIFO directly by software.
|
||||
|
||||
Add the necessary code to provide this "residue" value with a finer,
|
||||
sub-transfer granularity.
|
||||
|
||||
In order to prevent the occasional byte getting stuck in the DMA
|
||||
controller's internal buffers, restrict the destination memory width
|
||||
to the source register width.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 136 +++++++++++++++---
|
||||
drivers/dma/dw-axi-dmac/dw-axi-dmac.h | 3 +
|
||||
2 files changed, 118 insertions(+), 21 deletions(-)
|
||||
|
||||
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
|
||||
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dmapool.h>
|
||||
+#include <linux/dma-direct.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
@@ -79,6 +80,17 @@ axi_chan_iowrite64(struct axi_dma_chan *
|
||||
iowrite32(upper_32_bits(val), chan->chan_regs + reg + 4);
|
||||
}
|
||||
|
||||
+static inline u64
|
||||
+axi_chan_ioread64(struct axi_dma_chan *chan, u32 reg)
|
||||
+{
|
||||
+ /*
|
||||
+ * We split one 64 bit read into two 32 bit reads as some HW doesn't
|
||||
+ * support 64 bit access.
|
||||
+ */
|
||||
+ return ((u64)ioread32(chan->chan_regs + reg + 4) << 32) +
|
||||
+ ioread32(chan->chan_regs + reg);
|
||||
+}
|
||||
+
|
||||
static inline void axi_chan_config_write(struct axi_dma_chan *chan,
|
||||
struct axi_dma_chan_config *config)
|
||||
{
|
||||
@@ -86,7 +98,7 @@ static inline void axi_chan_config_write
|
||||
|
||||
cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
|
||||
config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
|
||||
- if (chan->chip->dw->hdata->reg_map_8_channels) {
|
||||
+ if (!chan->chip->dw->hdata->reg_map_cfg2) {
|
||||
cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
|
||||
config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
|
||||
config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
|
||||
@@ -214,7 +226,18 @@ static void axi_dma_hw_init(struct axi_d
|
||||
{
|
||||
int ret;
|
||||
u32 i;
|
||||
+ int retries = 1000;
|
||||
|
||||
+ axi_dma_iowrite32(chip, DMAC_RESET, 1);
|
||||
+ while (axi_dma_ioread32(chip, DMAC_RESET)) {
|
||||
+ retries--;
|
||||
+ if (!retries) {
|
||||
+ dev_err(chip->dev, "%s: DMAC failed to reset\n",
|
||||
+ __func__);
|
||||
+ return;
|
||||
+ }
|
||||
+ cpu_relax();
|
||||
+ }
|
||||
for (i = 0; i < chip->dw->hdata->nr_channels; i++) {
|
||||
axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL);
|
||||
axi_chan_disable(&chip->dw->chan[i]);
|
||||
@@ -276,7 +299,7 @@ static struct axi_dma_lli *axi_desc_get(
|
||||
static void axi_desc_put(struct axi_dma_desc *desc)
|
||||
{
|
||||
struct axi_dma_chan *chan = desc->chan;
|
||||
- int count = atomic_read(&chan->descs_allocated);
|
||||
+ u32 count = desc->hw_desc_count;
|
||||
struct axi_dma_hw_desc *hw_desc;
|
||||
int descs_put;
|
||||
|
||||
@@ -298,6 +321,48 @@ static void vchan_desc_put(struct virt_d
|
||||
axi_desc_put(vd_to_axi_desc(vdesc));
|
||||
}
|
||||
|
||||
+static u32 axi_dma_desc_src_pos(struct axi_dma_desc *desc, dma_addr_t addr)
|
||||
+{
|
||||
+ unsigned int idx = 0;
|
||||
+ u32 pos = 0;
|
||||
+
|
||||
+ while (pos < desc->length) {
|
||||
+ struct axi_dma_hw_desc *hw_desc = &desc->hw_desc[idx++];
|
||||
+ u32 len = hw_desc->len;
|
||||
+ dma_addr_t start = le64_to_cpu(hw_desc->lli->sar);
|
||||
+
|
||||
+ if (addr >= start && addr <= (start + len)) {
|
||||
+ pos += addr - start;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ pos += len;
|
||||
+ }
|
||||
+
|
||||
+ return pos;
|
||||
+}
|
||||
+
|
||||
+static u32 axi_dma_desc_dst_pos(struct axi_dma_desc *desc, dma_addr_t addr)
|
||||
+{
|
||||
+ unsigned int idx = 0;
|
||||
+ u32 pos = 0;
|
||||
+
|
||||
+ while (pos < desc->length) {
|
||||
+ struct axi_dma_hw_desc *hw_desc = &desc->hw_desc[idx++];
|
||||
+ u32 len = hw_desc->len;
|
||||
+ dma_addr_t start = le64_to_cpu(hw_desc->lli->dar);
|
||||
+
|
||||
+ if (addr >= start && addr <= (start + len)) {
|
||||
+ pos += addr - start;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ pos += len;
|
||||
+ }
|
||||
+
|
||||
+ return pos;
|
||||
+}
|
||||
+
|
||||
static enum dma_status
|
||||
dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie,
|
||||
struct dma_tx_state *txstate)
|
||||
@@ -307,10 +372,7 @@ dma_chan_tx_status(struct dma_chan *dcha
|
||||
enum dma_status status;
|
||||
u32 completed_length;
|
||||
unsigned long flags;
|
||||
- u32 completed_blocks;
|
||||
size_t bytes = 0;
|
||||
- u32 length;
|
||||
- u32 len;
|
||||
|
||||
status = dma_cookie_status(dchan, cookie, txstate);
|
||||
if (status == DMA_COMPLETE || !txstate)
|
||||
@@ -319,16 +381,31 @@ dma_chan_tx_status(struct dma_chan *dcha
|
||||
spin_lock_irqsave(&chan->vc.lock, flags);
|
||||
|
||||
vdesc = vchan_find_desc(&chan->vc, cookie);
|
||||
- if (vdesc) {
|
||||
- length = vd_to_axi_desc(vdesc)->length;
|
||||
- completed_blocks = vd_to_axi_desc(vdesc)->completed_blocks;
|
||||
- len = vd_to_axi_desc(vdesc)->hw_desc[0].len;
|
||||
- completed_length = completed_blocks * len;
|
||||
- bytes = length - completed_length;
|
||||
+ if (vdesc && vdesc == vchan_next_desc(&chan->vc)) {
|
||||
+ /* This descriptor is in-progress */
|
||||
+ struct axi_dma_desc *desc = vd_to_axi_desc(vdesc);
|
||||
+ dma_addr_t addr;
|
||||
+
|
||||
+ if (chan->direction == DMA_MEM_TO_DEV) {
|
||||
+ addr = axi_chan_ioread64(chan, CH_SAR);
|
||||
+ completed_length = axi_dma_desc_src_pos(desc, addr);
|
||||
+ } else if (chan->direction == DMA_DEV_TO_MEM) {
|
||||
+ addr = axi_chan_ioread64(chan, CH_DAR);
|
||||
+ completed_length = axi_dma_desc_dst_pos(desc, addr);
|
||||
+ } else {
|
||||
+ completed_length = 0;
|
||||
+ }
|
||||
+ bytes = desc->length - completed_length;
|
||||
+ } else if (vdesc) {
|
||||
+ /* Still in the queue so not started */
|
||||
+ bytes = vd_to_axi_desc(vdesc)->length;
|
||||
}
|
||||
|
||||
- spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
+ if (chan->is_paused && status == DMA_IN_PROGRESS)
|
||||
+ status = DMA_PAUSED;
|
||||
+
|
||||
dma_set_residue(txstate, bytes);
|
||||
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -516,7 +593,7 @@ static void dw_axi_dma_set_hw_channel(st
|
||||
unsigned long reg_value, val;
|
||||
|
||||
if (!chip->apb_regs) {
|
||||
- dev_err(chip->dev, "apb_regs not initialized\n");
|
||||
+ dev_dbg(chip->dev, "apb_regs not initialized\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -620,18 +697,25 @@ static int dw_axi_dma_set_hw_desc(struct
|
||||
switch (chan->direction) {
|
||||
case DMA_MEM_TO_DEV:
|
||||
reg_width = __ffs(chan->config.dst_addr_width);
|
||||
- device_addr = chan->config.dst_addr;
|
||||
+ device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr);
|
||||
ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
|
||||
mem_width << CH_CTL_L_SRC_WIDTH_POS |
|
||||
+ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS |
|
||||
+ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
|
||||
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
|
||||
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
|
||||
block_ts = len >> mem_width;
|
||||
break;
|
||||
case DMA_DEV_TO_MEM:
|
||||
reg_width = __ffs(chan->config.src_addr_width);
|
||||
- device_addr = chan->config.src_addr;
|
||||
+ /* Prevent partial access units getting lost */
|
||||
+ if (mem_width > reg_width)
|
||||
+ mem_width = reg_width;
|
||||
+ device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr);
|
||||
ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
|
||||
mem_width << CH_CTL_L_DST_WIDTH_POS |
|
||||
+ DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
|
||||
+ DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS |
|
||||
DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
|
||||
DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
|
||||
block_ts = len >> reg_width;
|
||||
@@ -667,9 +751,6 @@ static int dw_axi_dma_set_hw_desc(struct
|
||||
}
|
||||
|
||||
hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1);
|
||||
-
|
||||
- ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
|
||||
- DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS;
|
||||
hw_desc->lli->ctl_lo = cpu_to_le32(ctllo);
|
||||
|
||||
set_desc_src_master(hw_desc);
|
||||
@@ -764,6 +845,8 @@ dw_axi_dma_chan_prep_cyclic(struct dma_c
|
||||
src_addr += segment_len;
|
||||
}
|
||||
|
||||
+ desc->hw_desc_count = total_segments;
|
||||
+
|
||||
llp = desc->hw_desc[0].llp;
|
||||
|
||||
/* Managed transfer list */
|
||||
@@ -843,6 +926,8 @@ dw_axi_dma_chan_prep_slave_sg(struct dma
|
||||
} while (len >= segment_len);
|
||||
}
|
||||
|
||||
+ desc->hw_desc_count = loop;
|
||||
+
|
||||
/* Set end-of-link to the last link descriptor of list */
|
||||
set_desc_last(&desc->hw_desc[num_sgs - 1]);
|
||||
|
||||
@@ -950,6 +1035,8 @@ dma_chan_prep_dma_memcpy(struct dma_chan
|
||||
num++;
|
||||
}
|
||||
|
||||
+ desc->hw_desc_count = num;
|
||||
+
|
||||
/* Set end-of-link to the last link descriptor of list */
|
||||
set_desc_last(&desc->hw_desc[num - 1]);
|
||||
/* Managed transfer list */
|
||||
@@ -998,7 +1085,7 @@ static void axi_chan_dump_lli(struct axi
|
||||
static void axi_chan_list_dump_lli(struct axi_dma_chan *chan,
|
||||
struct axi_dma_desc *desc_head)
|
||||
{
|
||||
- int count = atomic_read(&chan->descs_allocated);
|
||||
+ u32 count = desc_head->hw_desc_count;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
@@ -1041,11 +1128,11 @@ out:
|
||||
|
||||
static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
|
||||
{
|
||||
- int count = atomic_read(&chan->descs_allocated);
|
||||
struct axi_dma_hw_desc *hw_desc;
|
||||
struct axi_dma_desc *desc;
|
||||
struct virt_dma_desc *vd;
|
||||
unsigned long flags;
|
||||
+ u32 count;
|
||||
u64 llp;
|
||||
int i;
|
||||
|
||||
@@ -1067,6 +1154,7 @@ static void axi_chan_block_xfer_complete
|
||||
if (chan->cyclic) {
|
||||
desc = vd_to_axi_desc(vd);
|
||||
if (desc) {
|
||||
+ count = desc->hw_desc_count;
|
||||
llp = lo_hi_readq(chan->chan_regs + CH_LLP);
|
||||
for (i = 0; i < count; i++) {
|
||||
hw_desc = &desc->hw_desc[i];
|
||||
@@ -1310,6 +1398,8 @@ static int parse_device_properties(struc
|
||||
chip->dw->hdata->nr_channels = tmp;
|
||||
if (tmp <= DMA_REG_MAP_CH_REF)
|
||||
chip->dw->hdata->reg_map_8_channels = true;
|
||||
+ else
|
||||
+ chip->dw->hdata->reg_map_cfg2 = true;
|
||||
|
||||
ret = device_property_read_u32(dev, "snps,dma-masters", &tmp);
|
||||
if (ret)
|
||||
@@ -1319,6 +1409,10 @@ static int parse_device_properties(struc
|
||||
|
||||
chip->dw->hdata->nr_masters = tmp;
|
||||
|
||||
+ ret = device_property_read_u32(dev, "snps,dma-targets", &tmp);
|
||||
+ if (!ret && tmp > 16)
|
||||
+ chip->dw->hdata->reg_map_cfg2 = true;
|
||||
+
|
||||
ret = device_property_read_u32(dev, "snps,data-width", &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
|
||||
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
|
||||
@@ -32,6 +32,8 @@ struct dw_axi_dma_hcfg {
|
||||
u32 axi_rw_burst_len;
|
||||
/* Register map for DMAX_NUM_CHANNELS <= 8 */
|
||||
bool reg_map_8_channels;
|
||||
+ /* Register map for DMAX_NUM_CHANNELS > 8 || DMAX_NUM_HS_IF > 16*/
|
||||
+ bool reg_map_cfg2;
|
||||
bool restrict_axi_burst_len;
|
||||
};
|
||||
|
||||
@@ -100,6 +102,7 @@ struct axi_dma_desc {
|
||||
|
||||
struct virt_dma_desc vd;
|
||||
struct axi_dma_chan *chan;
|
||||
+ u32 hw_desc_count;
|
||||
u32 completed_blocks;
|
||||
u32 length;
|
||||
u32 period_len;
|
@ -0,0 +1,64 @@
|
||||
From 8a9c0607ce0daa91c48faefd70ea73bda54ed0ae Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 29 Nov 2022 10:09:54 +0000
|
||||
Subject: [PATCH] spi: dw: Handle combined tx and rx messages
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/spi/spi-dw-core.c | 12 +++++++++---
|
||||
drivers/spi/spi-dw-mmio.c | 8 ++++++--
|
||||
2 files changed, 15 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/spi/spi-dw-core.c
|
||||
+++ b/drivers/spi/spi-dw-core.c
|
||||
@@ -244,8 +244,11 @@ static irqreturn_t dw_spi_transfer_handl
|
||||
*/
|
||||
if (irq_status & DW_SPI_INT_TXEI) {
|
||||
dw_writer(dws);
|
||||
- if (!dws->tx_len)
|
||||
+ if (!dws->tx_len) {
|
||||
dw_spi_mask_intr(dws, DW_SPI_INT_TXEI);
|
||||
+ if (!dws->rx_len)
|
||||
+ spi_finalize_current_transfer(dws->master);
|
||||
+ }
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -372,8 +375,11 @@ static void dw_spi_irq_setup(struct dw_s
|
||||
|
||||
dws->transfer_handler = dw_spi_transfer_handler;
|
||||
|
||||
- imask = DW_SPI_INT_TXEI | DW_SPI_INT_TXOI |
|
||||
- DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
|
||||
+ imask = 0;
|
||||
+ if (dws->tx_len)
|
||||
+ imask |= DW_SPI_INT_TXEI | DW_SPI_INT_TXOI;
|
||||
+ if (dws->rx_len)
|
||||
+ imask |= DW_SPI_INT_RXUI | DW_SPI_INT_RXOI | DW_SPI_INT_RXFI;
|
||||
dw_spi_umask_intr(dws, imask);
|
||||
}
|
||||
|
||||
--- a/drivers/spi/spi-dw-mmio.c
|
||||
+++ b/drivers/spi/spi-dw-mmio.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
+#include <linux/interrupt.h>
|
||||
|
||||
#include "spi-dw.h"
|
||||
|
||||
@@ -280,8 +281,11 @@ static int dw_spi_mmio_probe(struct plat
|
||||
dws->paddr = mem->start;
|
||||
|
||||
dws->irq = platform_get_irq(pdev, 0);
|
||||
- if (dws->irq < 0)
|
||||
- return dws->irq; /* -ENXIO */
|
||||
+ if (dws->irq < 0) {
|
||||
+ if (dws->irq != -ENXIO)
|
||||
+ return dws->irq; /* -ENXIO */
|
||||
+ dws->irq = IRQ_NOTCONNECTED;
|
||||
+ }
|
||||
|
||||
dwsmmio->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(dwsmmio->clk))
|
@ -0,0 +1,292 @@
|
||||
From 824f18efc8ad59e2783570ae2df83e2cd16b9f04 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 14 Feb 2023 14:03:54 +0000
|
||||
Subject: [PATCH] pwm: Add support for RP1 PWM
|
||||
|
||||
Add a driver for the RP1 PWM block.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
.../devicetree/bindings/pwm/pwm-rp1.yaml | 38 ++++
|
||||
drivers/pwm/Kconfig | 9 +
|
||||
drivers/pwm/Makefile | 1 +
|
||||
drivers/pwm/pwm-rp1.c | 203 ++++++++++++++++++
|
||||
4 files changed, 251 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/pwm/pwm-rp1.yaml
|
||||
create mode 100644 drivers/pwm/pwm-rp1.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/pwm/pwm-rp1.yaml
|
||||
@@ -0,0 +1,38 @@
|
||||
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
+%YAML 1.2
|
||||
+---
|
||||
+$id: http://devicetree.org/schemas/pwm/pwm-rp1.yaml#
|
||||
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
+
|
||||
+title: Raspberry Pi RP1 PWM controller
|
||||
+
|
||||
+maintainers:
|
||||
+ - Naushir Patuck <naush@raspberrypi.com>
|
||||
+
|
||||
+properties:
|
||||
+ compatible:
|
||||
+ enum:
|
||||
+ - raspberrypi,rp1-pwm
|
||||
+
|
||||
+ reg:
|
||||
+ maxItems: 1
|
||||
+
|
||||
+ "#pwm-cells":
|
||||
+ const: 3
|
||||
+
|
||||
+required:
|
||||
+ - compatible
|
||||
+ - reg
|
||||
+ - clocks
|
||||
+ - "#pwm-cells"
|
||||
+
|
||||
+additionalProperties: false
|
||||
+
|
||||
+examples:
|
||||
+ - |
|
||||
+ pwm0: pwm@98000 {
|
||||
+ compatible = "raspberrypi,rp1-pwm";
|
||||
+ reg = <0x0 0x98000 0x0 0x100>;
|
||||
+ clocks = <&rp1_sys>;
|
||||
+ #pwm-cells = <3>;
|
||||
+ };
|
||||
--- a/drivers/pwm/Kconfig
|
||||
+++ b/drivers/pwm/Kconfig
|
||||
@@ -451,6 +451,15 @@ config PWM_RASPBERRYPI_POE
|
||||
Enable Raspberry Pi firmware controller PWM bus used to control the
|
||||
official RPI PoE hat
|
||||
|
||||
+config PWM_RP1
|
||||
+ tristate "RP1 PWM support"
|
||||
+ depends on ARCH_BCM2835 || COMPILE_TEST
|
||||
+ help
|
||||
+ PWM framework driver for Raspberry Pi RP1 controller
|
||||
+
|
||||
+ To compile this driver as a module, choose M here: the module
|
||||
+ will be called pwm-rp1.
|
||||
+
|
||||
config PWM_RCAR
|
||||
tristate "Renesas R-Car PWM support"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
--- a/drivers/pwm/Makefile
|
||||
+++ b/drivers/pwm/Makefile
|
||||
@@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-om
|
||||
obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
|
||||
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
|
||||
obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o
|
||||
+obj-$(CONFIG_PWM_RP1) += pwm-rp1.o
|
||||
obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o
|
||||
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
|
||||
obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/pwm/pwm-rp1.c
|
||||
@@ -0,0 +1,203 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * pwm-rp1.c
|
||||
+ *
|
||||
+ * Raspberry Pi RP1 PWM.
|
||||
+ *
|
||||
+ * Copyright © 2023 Raspberry Pi Ltd.
|
||||
+ *
|
||||
+ * Author: Naushir Patuck (naush@raspberrypi.com)
|
||||
+ *
|
||||
+ * Based on the pwm-bcm2835 driver by:
|
||||
+ * Bart Tanghe <bart.tanghe@thomasmore.be>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/bitops.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/pwm.h>
|
||||
+
|
||||
+#define PWM_GLOBAL_CTRL 0x000
|
||||
+#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 16))
|
||||
+#define PWM_RANGE(x) (0x018 + ((x) * 16))
|
||||
+#define PWM_DUTY(x) (0x020 + ((x) * 16))
|
||||
+
|
||||
+/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */
|
||||
+#define PWM_CHANNEL_DEFAULT (BIT(8) + BIT(0))
|
||||
+#define PWM_CHANNEL_ENABLE(x) BIT(x)
|
||||
+#define PWM_POLARITY BIT(3)
|
||||
+#define SET_UPDATE BIT(31)
|
||||
+#define PWM_MODE_MASK GENMASK(1, 0)
|
||||
+
|
||||
+struct rp1_pwm {
|
||||
+ struct pwm_chip chip;
|
||||
+ struct device *dev;
|
||||
+ void __iomem *base;
|
||||
+ struct clk *clk;
|
||||
+};
|
||||
+
|
||||
+static inline struct rp1_pwm *to_rp1_pwm(struct pwm_chip *chip)
|
||||
+{
|
||||
+ return container_of(chip, struct rp1_pwm, chip);
|
||||
+}
|
||||
+
|
||||
+static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
+{
|
||||
+ struct rp1_pwm *pc = to_rp1_pwm(chip);
|
||||
+ u32 value;
|
||||
+
|
||||
+ value = readl(pc->base + PWM_GLOBAL_CTRL);
|
||||
+ value |= SET_UPDATE;
|
||||
+ writel(value, pc->base + PWM_GLOBAL_CTRL);
|
||||
+}
|
||||
+
|
||||
+static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
+{
|
||||
+ struct rp1_pwm *pc = to_rp1_pwm(chip);
|
||||
+
|
||||
+ writel(PWM_CHANNEL_DEFAULT, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
+{
|
||||
+ struct rp1_pwm *pc = to_rp1_pwm(chip);
|
||||
+ u32 value;
|
||||
+
|
||||
+ value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
|
||||
+ value &= ~PWM_MODE_MASK;
|
||||
+ writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
|
||||
+ rp1_pwm_apply_config(chip, pwm);
|
||||
+}
|
||||
+
|
||||
+static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
+ const struct pwm_state *state)
|
||||
+{
|
||||
+ struct rp1_pwm *pc = to_rp1_pwm(chip);
|
||||
+ unsigned long clk_rate = clk_get_rate(pc->clk);
|
||||
+ unsigned long clk_period;
|
||||
+ u32 value;
|
||||
+
|
||||
+ if (!clk_rate) {
|
||||
+ dev_err(pc->dev, "failed to get clock rate\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* set period */
|
||||
+ clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate);
|
||||
+
|
||||
+ writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period),
|
||||
+ pc->base + PWM_DUTY(pwm->hwpwm));
|
||||
+
|
||||
+ /* set duty cycle */
|
||||
+ writel(DIV_ROUND_CLOSEST(state->period, clk_period),
|
||||
+ pc->base + PWM_RANGE(pwm->hwpwm));
|
||||
+
|
||||
+ /* set polarity */
|
||||
+ value = readl(pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
|
||||
+ if (state->polarity == PWM_POLARITY_NORMAL)
|
||||
+ value &= ~PWM_POLARITY;
|
||||
+ else
|
||||
+ value |= PWM_POLARITY;
|
||||
+ writel(value, pc->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
|
||||
+
|
||||
+ /* enable/disable */
|
||||
+ value = readl(pc->base + PWM_GLOBAL_CTRL);
|
||||
+ if (state->enabled)
|
||||
+ value |= PWM_CHANNEL_ENABLE(pwm->hwpwm);
|
||||
+ else
|
||||
+ value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm);
|
||||
+ writel(value, pc->base + PWM_GLOBAL_CTRL);
|
||||
+
|
||||
+ rp1_pwm_apply_config(chip, pwm);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct pwm_ops rp1_pwm_ops = {
|
||||
+ .request = rp1_pwm_request,
|
||||
+ .free = rp1_pwm_free,
|
||||
+ .apply = rp1_pwm_apply,
|
||||
+ .owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static int rp1_pwm_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rp1_pwm *pc;
|
||||
+ struct resource *res;
|
||||
+ int ret;
|
||||
+
|
||||
+ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||
+ if (!pc)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ pc->dev = &pdev->dev;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ pc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
+ if (IS_ERR(pc->base))
|
||||
+ return PTR_ERR(pc->base);
|
||||
+
|
||||
+ pc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(pc->clk))
|
||||
+ return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
|
||||
+ "clock not found\n");
|
||||
+
|
||||
+ ret = clk_prepare_enable(pc->clk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ pc->chip.dev = &pdev->dev;
|
||||
+ pc->chip.ops = &rp1_pwm_ops;
|
||||
+ pc->chip.base = -1;
|
||||
+ pc->chip.npwm = 4;
|
||||
+ pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
+ pc->chip.of_pwm_n_cells = 3;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, pc);
|
||||
+
|
||||
+ ret = pwmchip_add(&pc->chip);
|
||||
+ if (ret < 0)
|
||||
+ goto add_fail;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+add_fail:
|
||||
+ clk_disable_unprepare(pc->clk);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rp1_pwm_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rp1_pwm *pc = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ clk_disable_unprepare(pc->clk);
|
||||
+
|
||||
+ pwmchip_remove(&pc->chip);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id rp1_pwm_of_match[] = {
|
||||
+ { .compatible = "raspberrypi,rp1-pwm" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);
|
||||
+
|
||||
+static struct platform_driver rp1_pwm_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rpi-pwm",
|
||||
+ .of_match_table = rp1_pwm_of_match,
|
||||
+ },
|
||||
+ .probe = rp1_pwm_probe,
|
||||
+ .remove = rp1_pwm_remove,
|
||||
+};
|
||||
+module_platform_driver(rp1_pwm_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com");
|
||||
+MODULE_DESCRIPTION("RP1 PWM driver");
|
||||
+MODULE_LICENSE("GPL");
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,75 @@
|
||||
From 3a419974ba02d32795a5ecfaf3c020f23173b6a1 Mon Sep 17 00:00:00 2001
|
||||
From: Naushir Patuck <naush@raspberrypi.com>
|
||||
Date: Tue, 14 Feb 2023 20:58:59 +0000
|
||||
Subject: [PATCH] v4l2: Add pisp compression format support to v4l2
|
||||
|
||||
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
|
||||
---
|
||||
drivers/media/v4l2-core/v4l2-ioctl.c | 12 ++++++++----
|
||||
include/uapi/linux/media-bus-format.h | 14 ++++++++++++++
|
||||
include/uapi/linux/videodev2.h | 12 ++++++++----
|
||||
3 files changed, 30 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
||||
@@ -1507,10 +1507,14 @@ static void v4l_fill_fmtdesc(struct v4l2
|
||||
case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break;
|
||||
case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break;
|
||||
case V4L2_PIX_FMT_RPI_BE: descr = "PiSP Opaque Format"; break;
|
||||
- case V4L2_PIX_FMT_PISP_COMP_RGGB:
|
||||
- case V4L2_PIX_FMT_PISP_COMP_GRBG:
|
||||
- case V4L2_PIX_FMT_PISP_COMP_GBRG:
|
||||
- case V4L2_PIX_FMT_PISP_COMP_BGGR: descr = "PiSP Bayer Compressed Format"; break;
|
||||
+ case V4L2_PIX_FMT_PISP_COMP1_RGGB:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP1_GRBG:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP1_GBRG:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP1_BGGR: descr = "PiSP Bayer Comp 1"; break;
|
||||
+ case V4L2_PIX_FMT_PISP_COMP2_RGGB:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP2_GRBG:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP2_GBRG:
|
||||
+ case V4L2_PIX_FMT_PISP_COMP2_BGGR: descr = "PiSP Bayer Comp 2"; break;
|
||||
default:
|
||||
if (fmt->description[0])
|
||||
return;
|
||||
--- a/include/uapi/linux/media-bus-format.h
|
||||
+++ b/include/uapi/linux/media-bus-format.h
|
||||
@@ -175,4 +175,18 @@
|
||||
/* Sensor ancillary metadata formats - next is 0x7002 */
|
||||
#define MEDIA_BUS_FMT_SENSOR_DATA 0x7002
|
||||
|
||||
+/* PiSP Formats */
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP1_RGGB 0x8001
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP1_GRBG 0x8002
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP1_GBRG 0x8003
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP1_BGGR 0x8004
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP2_RGGB 0x8005
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP2_GRBG 0x8006
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP2_GBRG 0x8007
|
||||
+#define MEDIA_BUS_FMT_PISP_COMP2_BGGR 0x8008
|
||||
+
|
||||
+#define MEDIA_BUS_FMT_PISP_FE_CONFIG 0x8100
|
||||
+#define MEDIA_BUS_FMT_PISP_FE_STATS 0x8101
|
||||
+#define MEDIA_BUS_FMT_PISP_BE_CONFIG 0x8200
|
||||
+
|
||||
#endif /* __LINUX_MEDIA_BUS_FORMAT_H */
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -795,10 +795,14 @@ struct v4l2_pix_format {
|
||||
|
||||
/* The pixel format for all our buffers (the precise format is found in the config buffer). */
|
||||
#define V4L2_PIX_FMT_RPI_BE v4l2_fourcc('R', 'P', 'B', 'P')
|
||||
-#define V4L2_PIX_FMT_PISP_COMP_RGGB v4l2_fourcc('P', 'C', 'R', 'G')
|
||||
-#define V4L2_PIX_FMT_PISP_COMP_GRBG v4l2_fourcc('P', 'C', 'G', 'R')
|
||||
-#define V4L2_PIX_FMT_PISP_COMP_GBRG v4l2_fourcc('P', 'C', 'G', 'B')
|
||||
-#define V4L2_PIX_FMT_PISP_COMP_BGGR v4l2_fourcc('P', 'C', 'B', 'G')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP1_RGGB v4l2_fourcc('P', 'C', '1', 'R')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP1_GRBG v4l2_fourcc('P', 'C', '1', 'G')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP1_GBRG v4l2_fourcc('P', 'C', '1', 'g')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP1_BGGR v4l2_fourcc('P', 'C', '1', 'B')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP2_RGGB v4l2_fourcc('P', 'C', '2', 'R')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP2_GRBG v4l2_fourcc('P', 'C', '2', 'G')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP2_GBRG v4l2_fourcc('P', 'C', '2', 'g')
|
||||
+#define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B')
|
||||
|
||||
/* SDR formats - used only for Software Defined Radio devices */
|
||||
#define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
From 2be65d1fd1f7d3cf6f59b58b53e285400f04a160 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 15 Feb 2023 09:46:35 +0000
|
||||
Subject: [PATCH] dt-bindings: net: cdns,macb: AXI tuning properties
|
||||
|
||||
Add optional properties to tune the AXI interface -
|
||||
cdns,aw2w-max-pipe, cdns,ar2r-max-pipe and cdns,use-aw2b-fill.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
.../devicetree/bindings/net/cdns,macb.yaml | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/net/cdns,macb.yaml
|
||||
+++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml
|
||||
@@ -121,6 +121,22 @@ properties:
|
||||
Node containing PHY children. If this node is not present, then PHYs will
|
||||
be direct children.
|
||||
|
||||
+ cdns,aw2w-max-pipe:
|
||||
+ $ref: /schemas/types.yaml#/definitions/uint32
|
||||
+ description:
|
||||
+ Maximum number of outstanding AXI write requests
|
||||
+
|
||||
+ cdns,ar2r-max-pipe:
|
||||
+ $ref: /schemas/types.yaml#/definitions/uint32
|
||||
+ description:
|
||||
+ Maximum number of outstanding AXI read requests
|
||||
+
|
||||
+ cdns,use-aw2b-fill:
|
||||
+ type: boolean
|
||||
+ description:
|
||||
+ If set, the maximum number of outstanding write transactions operates
|
||||
+ between the AW to B AXI channel, instead of the AW to W AXI channel.
|
||||
+
|
||||
patternProperties:
|
||||
"^ethernet-phy@[0-9a-f]$":
|
||||
type: object
|
@ -0,0 +1,29 @@
|
||||
From 9ef0615a5c5f93cb72af8df3a2dae6d23b106eb5 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Tue, 21 Feb 2023 21:26:16 +0000
|
||||
Subject: [PATCH] ASoC: dwc: list all supported sample sizes
|
||||
|
||||
The hardware configuration determines the maximum-supported sample size
|
||||
for each channel, but TCRx allows smaller sizes to be specified at run
|
||||
time. Include the smaller supported sizes in the formats array.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/dwc/dwc-i2s.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/sound/soc/dwc/dwc-i2s.c
|
||||
+++ b/sound/soc/dwc/dwc-i2s.c
|
||||
@@ -448,9 +448,9 @@ static const u32 bus_widths[COMP_MAX_DAT
|
||||
static const u32 formats[COMP_MAX_WORDSIZE] = {
|
||||
SNDRV_PCM_FMTBIT_S16_LE,
|
||||
SNDRV_PCM_FMTBIT_S16_LE,
|
||||
- SNDRV_PCM_FMTBIT_S24_LE,
|
||||
- SNDRV_PCM_FMTBIT_S24_LE,
|
||||
- SNDRV_PCM_FMTBIT_S32_LE,
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
|
||||
0,
|
||||
0,
|
||||
0
|
@ -0,0 +1,59 @@
|
||||
From 06f794e8cb227249e03893e4b4923ff58556eb60 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Thu, 4 Mar 2021 14:49:23 +0000
|
||||
Subject: [PATCH] ASoC: dwc: Support set_bclk_ratio
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/dwc/dwc-i2s.c | 35 +++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 35 insertions(+)
|
||||
|
||||
--- a/sound/soc/dwc/dwc-i2s.c
|
||||
+++ b/sound/soc/dwc/dwc-i2s.c
|
||||
@@ -351,11 +351,46 @@ static int dw_i2s_set_fmt(struct snd_soc
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int dw_i2s_set_bclk_ratio(struct snd_soc_dai *cpu_dai,
|
||||
+ unsigned int ratio)
|
||||
+{
|
||||
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
+ struct i2s_clk_config_data *config = &dev->config;
|
||||
+
|
||||
+ dev_err(dev->dev, "%s(%d)\n", __func__, ratio);
|
||||
+ switch (ratio) {
|
||||
+ case 32:
|
||||
+ config->data_width = 16;
|
||||
+ dev->ccr = 0x00;
|
||||
+ dev->xfer_resolution = 0x02;
|
||||
+ break;
|
||||
+
|
||||
+ case 48:
|
||||
+ config->data_width = 24;
|
||||
+ dev->ccr = 0x08;
|
||||
+ dev->xfer_resolution = 0x04;
|
||||
+ break;
|
||||
+
|
||||
+ case 64:
|
||||
+ config->data_width = 32;
|
||||
+ dev->ccr = 0x10;
|
||||
+ dev->xfer_resolution = 0x05;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ i2s_write_reg(dev->i2s_base, CCR, dev->ccr);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
|
||||
.hw_params = dw_i2s_hw_params,
|
||||
.prepare = dw_i2s_prepare,
|
||||
.trigger = dw_i2s_trigger,
|
||||
.set_fmt = dw_i2s_set_fmt,
|
||||
+ .set_bclk_ratio = dw_i2s_set_bclk_ratio,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
@ -0,0 +1,81 @@
|
||||
From b3b1177092d4d2ba6df74042d39aa42c5055f687 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 3 Jul 2023 09:08:16 +0100
|
||||
Subject: [PATCH] ASoC: dwc: Add DMACR handling
|
||||
|
||||
Add control of the DMACR register, which is required for paced DMA
|
||||
(i.e. DREQ) support.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/dwc/dwc-i2s.c | 13 ++++++++++---
|
||||
sound/soc/dwc/local.h | 13 +++++++++++++
|
||||
2 files changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/sound/soc/dwc/dwc-i2s.c
|
||||
+++ b/sound/soc/dwc/dwc-i2s.c
|
||||
@@ -185,9 +185,9 @@ static void i2s_stop(struct dw_i2s_dev *
|
||||
|
||||
static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
|
||||
{
|
||||
- u32 ch_reg;
|
||||
struct i2s_clk_config_data *config = &dev->config;
|
||||
-
|
||||
+ u32 ch_reg;
|
||||
+ u32 dmacr = 0;
|
||||
|
||||
i2s_disable_channels(dev, stream);
|
||||
|
||||
@@ -198,15 +198,22 @@ static void dw_i2s_config(struct dw_i2s_
|
||||
i2s_write_reg(dev->i2s_base, TFCR(ch_reg),
|
||||
dev->fifo_th - 1);
|
||||
i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
|
||||
+ dmacr |= (DMACR_DMAEN_TXCH0 << ch_reg);
|
||||
} else {
|
||||
i2s_write_reg(dev->i2s_base, RCR(ch_reg),
|
||||
dev->xfer_resolution);
|
||||
i2s_write_reg(dev->i2s_base, RFCR(ch_reg),
|
||||
dev->fifo_th - 1);
|
||||
i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
|
||||
+ dmacr |= (DMACR_DMAEN_RXCH0 << ch_reg);
|
||||
}
|
||||
-
|
||||
}
|
||||
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ dmacr |= DMACR_DMAEN_TX;
|
||||
+ else if (stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
+ dmacr |= DMACR_DMAEN_RX;
|
||||
+
|
||||
+ i2s_write_reg(dev->i2s_base, DMACR, dmacr);
|
||||
}
|
||||
|
||||
static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
--- a/sound/soc/dwc/local.h
|
||||
+++ b/sound/soc/dwc/local.h
|
||||
@@ -25,6 +25,8 @@
|
||||
#define RXFFR 0x014
|
||||
#define TXFFR 0x018
|
||||
|
||||
+#define DMACR 0x200
|
||||
+
|
||||
/* Interrupt status register fields */
|
||||
#define ISR_TXFO BIT(5)
|
||||
#define ISR_TXFE BIT(4)
|
||||
@@ -47,6 +49,17 @@
|
||||
#define RFF(x) (0x40 * x + 0x050)
|
||||
#define TFF(x) (0x40 * x + 0x054)
|
||||
|
||||
+#define DMACR_DMAEN_TX BIT(17)
|
||||
+#define DMACR_DMAEN_RX BIT(16)
|
||||
+#define DMACR_DMAEN_TXCH3 BIT(11)
|
||||
+#define DMACR_DMAEN_TXCH2 BIT(10)
|
||||
+#define DMACR_DMAEN_TXCH1 BIT(9)
|
||||
+#define DMACR_DMAEN_TXCH0 BIT(8)
|
||||
+#define DMACR_DMAEN_RXCH3 BIT(3)
|
||||
+#define DMACR_DMAEN_RXCH2 BIT(2)
|
||||
+#define DMACR_DMAEN_RXCH1 BIT(1)
|
||||
+#define DMACR_DMAEN_RXCH0 BIT(0)
|
||||
+
|
||||
/* I2SCOMPRegisters */
|
||||
#define I2S_COMP_PARAM_2 0x01F0
|
||||
#define I2S_COMP_PARAM_1 0x01F4
|
@ -0,0 +1,128 @@
|
||||
From e6baee4502c0228c79408b047096a1259a84353f Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Mon, 3 Jul 2023 10:14:43 +0100
|
||||
Subject: [PATCH] ASOC: dwc: Improve DMA shutdown
|
||||
|
||||
Disabling the I2S interface with outstanding transfers prevents the
|
||||
DMAC from shutting down, so keep it partially active after a stop.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/dwc/dwc-i2s.c | 72 ++++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 64 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/sound/soc/dwc/dwc-i2s.c
|
||||
+++ b/sound/soc/dwc/dwc-i2s.c
|
||||
@@ -165,24 +165,26 @@ static void i2s_start(struct dw_i2s_dev
|
||||
i2s_write_reg(dev->i2s_base, CER, 1);
|
||||
}
|
||||
|
||||
-static void i2s_stop(struct dw_i2s_dev *dev,
|
||||
- struct snd_pcm_substream *substream)
|
||||
+static void i2s_pause(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
|
||||
{
|
||||
|
||||
i2s_clear_irqs(dev, substream->stream);
|
||||
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
- i2s_write_reg(dev->i2s_base, ITER, 0);
|
||||
- else
|
||||
- i2s_write_reg(dev->i2s_base, IRER, 0);
|
||||
|
||||
i2s_disable_irqs(dev, substream->stream, 8);
|
||||
|
||||
if (!dev->active) {
|
||||
i2s_write_reg(dev->i2s_base, CER, 0);
|
||||
- i2s_write_reg(dev->i2s_base, IER, 0);
|
||||
+ /* Keep the device enabled until the shutdown - do not clear IER */
|
||||
}
|
||||
}
|
||||
|
||||
+static void i2s_stop(struct dw_i2s_dev *dev, struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ i2s_clear_irqs(dev, substream->stream);
|
||||
+
|
||||
+ i2s_disable_irqs(dev, substream->stream, 8);
|
||||
+}
|
||||
+
|
||||
static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
|
||||
{
|
||||
struct i2s_clk_config_data *config = &dev->config;
|
||||
@@ -288,6 +290,55 @@ static int dw_i2s_hw_params(struct snd_p
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int dw_i2s_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *cpu_dai)
|
||||
+{
|
||||
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
+ union dw_i2s_snd_dma_data *dma_data = NULL;
|
||||
+ u32 dmacr;
|
||||
+
|
||||
+ dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name);
|
||||
+ if (!(dev->capability & DWC_I2S_RECORD) &&
|
||||
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (!(dev->capability & DWC_I2S_PLAY) &&
|
||||
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ dw_i2s_config(dev, substream->stream);
|
||||
+ dmacr = i2s_read_reg(dev->i2s_base, DMACR);
|
||||
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ dma_data = &dev->play_dma_data;
|
||||
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
+ dma_data = &dev->capture_dma_data;
|
||||
+
|
||||
+ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
|
||||
+ i2s_write_reg(dev->i2s_base, DMACR, dmacr);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ dev_dbg(dev->dev, "%s(%s)\n", __func__, substream->name);
|
||||
+ i2s_disable_channels(dev, substream->stream);
|
||||
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ i2s_write_reg(dev->i2s_base, ITER, 0);
|
||||
+ else
|
||||
+ i2s_write_reg(dev->i2s_base, IRER, 0);
|
||||
+
|
||||
+ i2s_disable_irqs(dev, substream->stream, 8);
|
||||
+
|
||||
+ if (!dev->active) {
|
||||
+ i2s_write_reg(dev->i2s_base, CER, 0);
|
||||
+ i2s_write_reg(dev->i2s_base, IER, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int dw_i2s_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
@@ -315,9 +366,12 @@ static int dw_i2s_trigger(struct snd_pcm
|
||||
i2s_start(dev, substream);
|
||||
break;
|
||||
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ dev->active--;
|
||||
+ i2s_pause(dev, substream);
|
||||
+ break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
dev->active--;
|
||||
i2s_stop(dev, substream);
|
||||
break;
|
||||
@@ -394,6 +448,8 @@ static int dw_i2s_set_bclk_ratio(struct
|
||||
|
||||
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
|
||||
.hw_params = dw_i2s_hw_params,
|
||||
+ .startup = dw_i2s_startup,
|
||||
+ .shutdown = dw_i2s_shutdown,
|
||||
.prepare = dw_i2s_prepare,
|
||||
.trigger = dw_i2s_trigger,
|
||||
.set_fmt = dw_i2s_set_fmt,
|
@ -0,0 +1,88 @@
|
||||
From 9c6694c24f26ea435165431d41c72451fadbd753 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 21 Jul 2023 12:07:16 +0100
|
||||
Subject: [PATCH] ASOC: dwc: Fix 16-bit audio handling
|
||||
|
||||
IMO the Synopsys datasheet could be clearer in this area, but it seems
|
||||
that the DMA data ports (DMATX and DMARX) expect left and right samples
|
||||
in alternate writes; if a stereo pair is pushed in a single 32-bit
|
||||
write, the upper half is ignored, leading to double speed audio with a
|
||||
confused stereo image. Make sure the necessary changes happen by
|
||||
updating the DMA configuration data in the hw_params method.
|
||||
|
||||
The set_bclk_ratio change was made at a time when it looked like it
|
||||
could be causing an error, but I think the division of responsibilities
|
||||
is clearer this way (and the kernel log clearer without the info-level
|
||||
message).
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/dwc/dwc-i2s.c | 22 +++++++++++++++-------
|
||||
1 file changed, 15 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/sound/soc/dwc/dwc-i2s.c
|
||||
+++ b/sound/soc/dwc/dwc-i2s.c
|
||||
@@ -223,23 +223,34 @@ static int dw_i2s_hw_params(struct snd_p
|
||||
{
|
||||
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
struct i2s_clk_config_data *config = &dev->config;
|
||||
+ union dw_i2s_snd_dma_data *dma_data = NULL;
|
||||
int ret;
|
||||
|
||||
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
+ dma_data = &dev->play_dma_data;
|
||||
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
|
||||
+ dma_data = &dev->capture_dma_data;
|
||||
+ else
|
||||
+ return -1;
|
||||
+
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
config->data_width = 16;
|
||||
+ dma_data->dt.addr_width = 2;
|
||||
dev->ccr = 0x00;
|
||||
dev->xfer_resolution = 0x02;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
config->data_width = 24;
|
||||
+ dma_data->dt.addr_width = 4;
|
||||
dev->ccr = 0x08;
|
||||
dev->xfer_resolution = 0x04;
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
config->data_width = 32;
|
||||
+ dma_data->dt.addr_width = 4;
|
||||
dev->ccr = 0x10;
|
||||
dev->xfer_resolution = 0x05;
|
||||
break;
|
||||
@@ -418,24 +429,21 @@ static int dw_i2s_set_bclk_ratio(struct
|
||||
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
struct i2s_clk_config_data *config = &dev->config;
|
||||
|
||||
- dev_err(dev->dev, "%s(%d)\n", __func__, ratio);
|
||||
+ dev_dbg(dev->dev, "%s(%d)\n", __func__, ratio);
|
||||
+ if (ratio < config->data_width * 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
switch (ratio) {
|
||||
case 32:
|
||||
- config->data_width = 16;
|
||||
dev->ccr = 0x00;
|
||||
- dev->xfer_resolution = 0x02;
|
||||
break;
|
||||
|
||||
case 48:
|
||||
- config->data_width = 24;
|
||||
dev->ccr = 0x08;
|
||||
- dev->xfer_resolution = 0x04;
|
||||
break;
|
||||
|
||||
case 64:
|
||||
- config->data_width = 32;
|
||||
dev->ccr = 0x10;
|
||||
- dev->xfer_resolution = 0x05;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
@ -0,0 +1,304 @@
|
||||
From f476db1b71e8b82e5299168f963a2fefb7a395e2 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 1 Sep 2023 14:07:48 +0100
|
||||
Subject: [PATCH] ASoC: bcm: Remove dependency on BCM2835 I2S
|
||||
|
||||
These soundcard drivers don't rely on a specific I2S interface, so
|
||||
remove the dependency declarations.
|
||||
|
||||
See: https://github.com/raspberrypi/linux-2712/issues/111
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
sound/soc/bcm/Kconfig | 40 +---------------------------------------
|
||||
1 file changed, 1 insertion(+), 39 deletions(-)
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -29,13 +29,11 @@ config SND_BCM63XX_I2S_WHISTLER
|
||||
|
||||
config SND_BCM2708_SOC_CHIPDIP_DAC
|
||||
tristate "Support for the ChipDip DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
help
|
||||
Say Y or M if you want to add support for the ChipDip DAC soundcard
|
||||
|
||||
config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
|
||||
tristate "Support for Google voiceHAT soundcard"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_VOICEHAT
|
||||
select SND_RPI_SIMPLE_SOUNDCARD
|
||||
help
|
||||
@@ -43,7 +41,6 @@ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SO
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DAC
|
||||
tristate "Support for HifiBerry DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM5102A
|
||||
select SND_RPI_SIMPLE_SOUNDCARD
|
||||
help
|
||||
@@ -51,7 +48,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
|
||||
tristate "Support for HifiBerry DAC+"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x
|
||||
select SND_SOC_TPA6130A2
|
||||
select COMMON_CLK_HIFIBERRY_DACPRO
|
||||
@@ -60,7 +56,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
|
||||
tristate "Support for HifiBerry DAC+ HD"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM179X_I2C
|
||||
select COMMON_CLK_HIFIBERRY_DACPLUSHD
|
||||
help
|
||||
@@ -68,7 +63,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
|
||||
tristate "Support for HifiBerry DAC+ADC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
select SND_SOC_DMIC
|
||||
select COMMON_CLK_HIFIBERRY_DACPRO
|
||||
@@ -77,7 +71,6 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO
|
||||
tristate "Support for HifiBerry DAC+ADC PRO"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
select SND_SOC_PCM186X_I2C
|
||||
select SND_SOC_TPA6130A2
|
||||
@@ -87,29 +80,25 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP
|
||||
tristate "Support for HifiBerry DAC+DSP"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_RPI_SIMPLE_SOUNDCARD
|
||||
help
|
||||
Say Y or M if you want to add support for HifiBerry DSP-DAC.
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_DIGI
|
||||
tristate "Support for HifiBerry Digi"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8804
|
||||
help
|
||||
Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
|
||||
|
||||
config SND_BCM2708_SOC_HIFIBERRY_AMP
|
||||
tristate "Support for the HifiBerry Amp"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_TAS5713
|
||||
select SND_RPI_SIMPLE_SOUNDCARD
|
||||
help
|
||||
Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
|
||||
|
||||
- config SND_BCM2708_SOC_PIFI_40
|
||||
+config SND_BCM2708_SOC_PIFI_40
|
||||
tristate "Support for the PiFi-40 amp"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_TAS571X
|
||||
select SND_PIFI_40
|
||||
help
|
||||
@@ -117,7 +106,6 @@ config SND_BCM2708_SOC_HIFIBERRY_AMP
|
||||
|
||||
config SND_BCM2708_SOC_RPI_CIRRUS
|
||||
tristate "Support for Cirrus Logic Audio Card"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM5102
|
||||
select SND_SOC_WM8804
|
||||
help
|
||||
@@ -126,7 +114,6 @@ config SND_BCM2708_SOC_RPI_CIRRUS
|
||||
|
||||
config SND_BCM2708_SOC_RPI_DAC
|
||||
tristate "Support for RPi-DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM1794A
|
||||
select SND_RPI_SIMPLE_SOUNDCARD
|
||||
help
|
||||
@@ -134,14 +121,12 @@ config SND_BCM2708_SOC_RPI_DAC
|
||||
|
||||
config SND_BCM2708_SOC_RPI_PROTO
|
||||
tristate "Support for Rpi-PROTO"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8731_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
|
||||
|
||||
config SND_BCM2708_SOC_JUSTBOOM_BOTH
|
||||
tristate "Support for simultaneous JustBoom Digi and JustBoom DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8804
|
||||
select SND_SOC_PCM512x
|
||||
help
|
||||
@@ -153,14 +138,12 @@ config SND_BCM2708_SOC_JUSTBOOM_BOTH
|
||||
|
||||
config SND_BCM2708_SOC_JUSTBOOM_DAC
|
||||
tristate "Support for JustBoom DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x
|
||||
help
|
||||
Say Y or M if you want to add support for JustBoom DAC.
|
||||
|
||||
config SND_BCM2708_SOC_JUSTBOOM_DIGI
|
||||
tristate "Support for JustBoom Digi"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8804
|
||||
select SND_RPI_WM8804_SOUNDCARD
|
||||
help
|
||||
@@ -168,21 +151,18 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI
|
||||
|
||||
config SND_BCM2708_SOC_IQAUDIO_CODEC
|
||||
tristate "Support for IQaudIO-CODEC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_DA7213
|
||||
help
|
||||
Say Y or M if you want to add support for IQaudIO-CODEC.
|
||||
|
||||
config SND_BCM2708_SOC_IQAUDIO_DAC
|
||||
tristate "Support for IQaudIO-DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for IQaudIO-DAC.
|
||||
|
||||
config SND_BCM2708_SOC_IQAUDIO_DIGI
|
||||
tristate "Support for IQAudIO Digi"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8804
|
||||
select SND_RPI_WM8804_SOUNDCARD
|
||||
help
|
||||
@@ -190,14 +170,12 @@ config SND_BCM2708_SOC_IQAUDIO_DIGI
|
||||
|
||||
config SND_BCM2708_SOC_I_SABRE_Q2M
|
||||
tristate "Support for Audiophonics I-Sabre Q2M DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_I_SABRE_CODEC
|
||||
help
|
||||
Say Y or M if you want to add support for Audiophonics I-SABRE Q2M DAC
|
||||
|
||||
config SND_BCM2708_SOC_ADAU1977_ADC
|
||||
tristate "Support for ADAU1977 ADC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_ADAU1977_I2C
|
||||
select SND_RPI_SIMPLE_SOUNDCARD
|
||||
help
|
||||
@@ -205,35 +183,30 @@ config SND_BCM2708_SOC_ADAU1977_ADC
|
||||
|
||||
config SND_AUDIOINJECTOR_PI_SOUNDCARD
|
||||
tristate "Support for audioinjector.net Pi add on soundcard"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8731_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for audioinjector.net Pi Hat
|
||||
|
||||
config SND_AUDIOINJECTOR_OCTO_SOUNDCARD
|
||||
tristate "Support for audioinjector.net Octo channel (Hat) soundcard"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_CS42XX8_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for audioinjector.net octo add on
|
||||
|
||||
config SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD
|
||||
tristate "Support for audioinjector.net isolated DAC and ADC soundcard"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_CS4271_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for audioinjector.net isolated soundcard
|
||||
|
||||
config SND_AUDIOSENSE_PI
|
||||
tristate "Support for AudioSense Add-On Soundcard"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_TLV320AIC32X4_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for tlv320aic32x4 add-on
|
||||
|
||||
config SND_DIGIDAC1_SOUNDCARD
|
||||
tristate "Support for Red Rocks Audio DigiDAC1"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8804
|
||||
select SND_SOC_WM8741
|
||||
help
|
||||
@@ -241,35 +214,30 @@ config SND_DIGIDAC1_SOUNDCARD
|
||||
|
||||
config SND_BCM2708_SOC_DIONAUDIO_LOCO
|
||||
tristate "Support for Dion Audio LOCO DAC-AMP"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM5102a
|
||||
help
|
||||
Say Y or M if you want to add support for Dion Audio LOCO.
|
||||
|
||||
config SND_BCM2708_SOC_DIONAUDIO_LOCO_V2
|
||||
tristate "Support for Dion Audio LOCO-V2 DAC-AMP"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM5122
|
||||
help
|
||||
Say Y or M if you want to add support for Dion Audio LOCO-V2.
|
||||
|
||||
config SND_BCM2708_SOC_ALLO_PIANO_DAC
|
||||
tristate "Support for Allo Piano DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for Allo Piano DAC.
|
||||
|
||||
config SND_BCM2708_SOC_ALLO_PIANO_DAC_PLUS
|
||||
tristate "Support for Allo Piano DAC Plus"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for Allo Piano DAC Plus.
|
||||
|
||||
config SND_BCM2708_SOC_ALLO_BOSS_DAC
|
||||
tristate "Support for Allo Boss DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_PCM512x_I2C
|
||||
select COMMON_CLK_HIFIBERRY_DACPRO
|
||||
help
|
||||
@@ -277,7 +245,6 @@ config SND_BCM2708_SOC_ALLO_BOSS_DAC
|
||||
|
||||
config SND_BCM2708_SOC_ALLO_BOSS2_DAC
|
||||
tristate "Support for Allo Boss2 DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select SND_AUDIO_GRAPH_CARD
|
||||
@@ -286,7 +253,6 @@ config SND_BCM2708_SOC_ALLO_BOSS2_DAC
|
||||
|
||||
config SND_BCM2708_SOC_ALLO_DIGIONE
|
||||
tristate "Support for Allo DigiOne"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_WM8804
|
||||
select SND_RPI_WM8804_SOUNDCARD
|
||||
help
|
||||
@@ -294,7 +260,6 @@ config SND_BCM2708_SOC_ALLO_DIGIONE
|
||||
|
||||
config SND_BCM2708_SOC_ALLO_KATANA_DAC
|
||||
tristate "Support for Allo Katana DAC"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select SND_AUDIO_GRAPH_CARD
|
||||
@@ -303,14 +268,12 @@ config SND_BCM2708_SOC_ALLO_KATANA_DAC
|
||||
|
||||
config SND_BCM2708_SOC_FE_PI_AUDIO
|
||||
tristate "Support for Fe-Pi-Audio"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_SGTL5000
|
||||
help
|
||||
Say Y or M if you want to add support for Fe-Pi-Audio.
|
||||
|
||||
config SND_PISOUND
|
||||
tristate "Support for Blokas Labs pisound"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_RAWMIDI
|
||||
help
|
||||
Say Y or M if you want to add support for Blokas Labs pisound.
|
||||
@@ -328,7 +291,6 @@ config SND_RPI_WM8804_SOUNDCARD
|
||||
|
||||
config SND_DACBERRY400
|
||||
tristate "Support for DACBERRY400 Soundcard"
|
||||
- depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
select SND_SOC_TLV320AIC3X_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for tlv320aic3x add-on
|
@ -0,0 +1,343 @@
|
||||
From cad3c92ff0c1a5fa539d08b695b0f6b326924890 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Thu, 2 Mar 2023 18:04:42 +0000
|
||||
Subject: [PATCH] hwmon: Add RP1 ADC and temperature driver
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/hwmon/Kconfig | 7 +
|
||||
drivers/hwmon/Makefile | 1 +
|
||||
drivers/hwmon/rp1-adc.c | 301 ++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 309 insertions(+)
|
||||
create mode 100644 drivers/hwmon/rp1-adc.c
|
||||
|
||||
--- a/drivers/hwmon/Kconfig
|
||||
+++ b/drivers/hwmon/Kconfig
|
||||
@@ -2331,6 +2331,13 @@ config SENSORS_INTEL_M10_BMC_HWMON
|
||||
sensors monitor various telemetry data of different components on the
|
||||
card, e.g. board temperature, FPGA core temperature/voltage/current.
|
||||
|
||||
+config SENSORS_RP1_ADC
|
||||
+ tristate "RP1 ADC and temperature sensor driver"
|
||||
+ depends on MFD_RP1
|
||||
+ help
|
||||
+ Say yes here to enable support for the voltage and temperature
|
||||
+ sensors of the Raspberry Pi RP1 peripheral chip.
|
||||
+
|
||||
if ACPI
|
||||
|
||||
comment "ACPI drivers"
|
||||
--- a/drivers/hwmon/Makefile
|
||||
+++ b/drivers/hwmon/Makefile
|
||||
@@ -173,6 +173,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591
|
||||
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
|
||||
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
|
||||
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
|
||||
+obj-$(CONFIG_SENSORS_RP1_ADC) += rp1-adc.o
|
||||
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
|
||||
obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/hwmon/rp1-adc.c
|
||||
@@ -0,0 +1,301 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Driver for the RP1 ADC and temperature sensor
|
||||
+ * Copyright (C) 2023 Raspberry Pi Ltd.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/hwmon.h>
|
||||
+#include <linux/hwmon-sysfs.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regulator/consumer.h>
|
||||
+
|
||||
+#define MODULE_NAME "rp1-adc"
|
||||
+
|
||||
+#define RP1_ADC_CS 0x00
|
||||
+#define RP1_ADC_RESULT 0x04
|
||||
+#define RP1_ADC_FCS 0x08
|
||||
+#define RP1_ADC_FIFO 0x0c
|
||||
+#define RP1_ADC_DIV 0x10
|
||||
+
|
||||
+#define RP1_ADC_INTR 0x14
|
||||
+#define RP1_ADC_INTE 0x18
|
||||
+#define RP1_ADC_INTF 0x1c
|
||||
+#define RP1_ADC_INTS 0x20
|
||||
+
|
||||
+#define RP1_ADC_RWTYPE_SET 0x2000
|
||||
+#define RP1_ADC_RWTYPE_CLR 0x3000
|
||||
+
|
||||
+#define RP1_ADC_CS_RROBIN_MASK 0x1f
|
||||
+#define RP1_ADC_CS_RROBIN_SHIFT 16
|
||||
+#define RP1_ADC_CS_AINSEL_MASK 0x7
|
||||
+#define RP1_ADC_CS_AINSEL_SHIFT 12
|
||||
+#define RP1_ADC_CS_ERR_STICKY 0x400
|
||||
+#define RP1_ADC_CS_ERR 0x200
|
||||
+#define RP1_ADC_CS_READY 0x100
|
||||
+#define RP1_ADC_CS_START_MANY 0x8
|
||||
+#define RP1_ADC_CS_START_ONCE 0x4
|
||||
+#define RP1_ADC_CS_TS_EN 0x2
|
||||
+#define RP1_ADC_CS_EN 0x1
|
||||
+
|
||||
+#define RP1_ADC_FCS_THRESH_MASK 0xf
|
||||
+#define RP1_ADC_FCS_THRESH_SHIFT 24
|
||||
+#define RP1_ADC_FCS_LEVEL_MASK 0xf
|
||||
+#define RP1_ADC_FCS_LEVEL_SHIFT 16
|
||||
+#define RP1_ADC_FCS_OVER 0x800
|
||||
+#define RP1_ADC_FCS_UNDER 0x400
|
||||
+#define RP1_ADC_FCS_FULL 0x200
|
||||
+#define RP1_ADC_FCS_EMPTY 0x100
|
||||
+#define RP1_ADC_FCS_DREQ_EN 0x8
|
||||
+#define RP1_ADC_FCS_ERR 0x4
|
||||
+#define RP1_ADC_FCS_SHIFR 0x2
|
||||
+#define RP1_ADC_FCS_EN 0x1
|
||||
+
|
||||
+#define RP1_ADC_FIFO_ERR 0x8000
|
||||
+#define RP1_ADC_FIFO_VAL_MASK 0xfff
|
||||
+
|
||||
+#define RP1_ADC_DIV_INT_MASK 0xffff
|
||||
+#define RP1_ADC_DIV_INT_SHIFT 8
|
||||
+#define RP1_ADC_DIV_FRAC_MASK 0xff
|
||||
+#define RP1_ADC_DIV_FRAC_SHIFT 0
|
||||
+
|
||||
+struct rp1_adc_data {
|
||||
+ void __iomem *base;
|
||||
+ spinlock_t lock;
|
||||
+ struct device *hwmon_dev;
|
||||
+ int vref_mv;
|
||||
+};
|
||||
+
|
||||
+static int rp1_adc_ready_wait(struct rp1_adc_data *data)
|
||||
+{
|
||||
+ int retries = 10;
|
||||
+
|
||||
+ while (retries && !(readl(data->base + RP1_ADC_CS) & RP1_ADC_CS_READY))
|
||||
+ retries--;
|
||||
+
|
||||
+ return retries ? 0 : -EIO;
|
||||
+}
|
||||
+
|
||||
+static int rp1_adc_read(struct rp1_adc_data *data,
|
||||
+ struct device_attribute *devattr, unsigned int *val)
|
||||
+{
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ int channel = attr->index;
|
||||
+ int ret;
|
||||
+
|
||||
+ spin_lock(&data->lock);
|
||||
+
|
||||
+ writel(RP1_ADC_CS_AINSEL_MASK << RP1_ADC_CS_AINSEL_SHIFT,
|
||||
+ data->base + RP1_ADC_RWTYPE_CLR + RP1_ADC_CS);
|
||||
+ writel(channel << RP1_ADC_CS_AINSEL_SHIFT,
|
||||
+ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS);
|
||||
+ writel(RP1_ADC_CS_START_ONCE,
|
||||
+ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS);
|
||||
+
|
||||
+ ret = rp1_adc_ready_wait(data);
|
||||
+ if (!ret)
|
||||
+ *val = readl(data->base + RP1_ADC_RESULT);
|
||||
+
|
||||
+ spin_unlock(&data->lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rp1_adc_to_mv(struct rp1_adc_data *data, unsigned int val)
|
||||
+{
|
||||
+ return ((u64)data->vref_mv * val) / 0xfff;
|
||||
+}
|
||||
+
|
||||
+static ssize_t rp1_adc_show(struct device *dev,
|
||||
+ struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct rp1_adc_data *data = dev_get_drvdata(dev);
|
||||
+ unsigned int val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = rp1_adc_read(data, devattr, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", rp1_adc_to_mv(data, val));
|
||||
+}
|
||||
+
|
||||
+static ssize_t rp1_adc_temp_show(struct device *dev,
|
||||
+ struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct rp1_adc_data *data = dev_get_drvdata(dev);
|
||||
+ unsigned int val;
|
||||
+ int ret, mv, mc;
|
||||
+
|
||||
+ writel(RP1_ADC_CS_TS_EN,
|
||||
+ data->base + RP1_ADC_RWTYPE_SET + RP1_ADC_CS);
|
||||
+ ret = rp1_adc_read(data, devattr, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ mv = rp1_adc_to_mv(data, val);
|
||||
+
|
||||
+ /* T = 27 - (ADC_voltage - 0.706)/0.001721 */
|
||||
+
|
||||
+ mc = 27000 - DIV_ROUND_CLOSEST((mv - 706) * (s64)1000000, 1721);
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", mc);
|
||||
+}
|
||||
+
|
||||
+static ssize_t rp1_adc_raw_show(struct device *dev,
|
||||
+ struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct rp1_adc_data *data = dev_get_drvdata(dev);
|
||||
+ unsigned int val;
|
||||
+ int ret = rp1_adc_read(data, devattr, &val);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return sprintf(buf, "%u\n", val);
|
||||
+}
|
||||
+
|
||||
+static ssize_t rp1_adc_temp_raw_show(struct device *dev,
|
||||
+ struct device_attribute *devattr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct rp1_adc_data *data = dev_get_drvdata(dev);
|
||||
+ unsigned int val;
|
||||
+ int ret = rp1_adc_read(data, devattr, &val);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return sprintf(buf, "%u\n", val);
|
||||
+}
|
||||
+
|
||||
+static SENSOR_DEVICE_ATTR_RO(in1_input, rp1_adc, 0);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in2_input, rp1_adc, 1);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in3_input, rp1_adc, 2);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in4_input, rp1_adc, 3);
|
||||
+static SENSOR_DEVICE_ATTR_RO(temp1_input, rp1_adc_temp, 4);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in1_raw, rp1_adc_raw, 0);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in2_raw, rp1_adc_raw, 1);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in3_raw, rp1_adc_raw, 2);
|
||||
+static SENSOR_DEVICE_ATTR_RO(in4_raw, rp1_adc_raw, 3);
|
||||
+static SENSOR_DEVICE_ATTR_RO(temp1_raw, rp1_adc_temp_raw, 4);
|
||||
+
|
||||
+static struct attribute *rp1_adc_attrs[] = {
|
||||
+ &sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in1_raw.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in2_raw.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in3_raw.dev_attr.attr,
|
||||
+ &sensor_dev_attr_in4_raw.dev_attr.attr,
|
||||
+ &sensor_dev_attr_temp1_raw.dev_attr.attr,
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+static umode_t rp1_adc_is_visible(struct kobject *kobj,
|
||||
+ struct attribute *attr, int index)
|
||||
+{
|
||||
+ return 0444;
|
||||
+}
|
||||
+
|
||||
+static const struct attribute_group rp1_adc_group = {
|
||||
+ .attrs = rp1_adc_attrs,
|
||||
+ .is_visible = rp1_adc_is_visible,
|
||||
+};
|
||||
+__ATTRIBUTE_GROUPS(rp1_adc);
|
||||
+
|
||||
+static int __init rp1_adc_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rp1_adc_data *data;
|
||||
+ struct regulator *reg;
|
||||
+ struct clk *clk;
|
||||
+ int vref_uv, ret;
|
||||
+
|
||||
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ spin_lock_init(&data->lock);
|
||||
+
|
||||
+ data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
+ if (IS_ERR(data->base))
|
||||
+ return PTR_ERR(data->base);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, data);
|
||||
+
|
||||
+ clk = devm_clk_get(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(clk))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ clk_set_rate(clk, 50000000);
|
||||
+ clk_prepare_enable(clk);
|
||||
+
|
||||
+ reg = devm_regulator_get(&pdev->dev, "vref");
|
||||
+ if (IS_ERR(reg))
|
||||
+ return PTR_ERR(reg);
|
||||
+
|
||||
+ vref_uv = regulator_get_voltage(reg);
|
||||
+ data->vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
|
||||
+
|
||||
+ data->hwmon_dev =
|
||||
+ devm_hwmon_device_register_with_groups(&pdev->dev,
|
||||
+ "rp1_adc",
|
||||
+ data,
|
||||
+ rp1_adc_groups);
|
||||
+ if (IS_ERR(data->hwmon_dev)) {
|
||||
+ ret = PTR_ERR(data->hwmon_dev);
|
||||
+ dev_err(&pdev->dev, "hwmon_device_register failed with %d.\n", ret);
|
||||
+ goto err_register;
|
||||
+ }
|
||||
+
|
||||
+ /* Disable interrupts */
|
||||
+ writel(0, data->base + RP1_ADC_INTE);
|
||||
+
|
||||
+ /* Enable the block, clearing any sticky error */
|
||||
+ writel(RP1_ADC_CS_EN | RP1_ADC_CS_ERR_STICKY, data->base + RP1_ADC_CS);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_register:
|
||||
+ sysfs_remove_group(&pdev->dev.kobj, &rp1_adc_group);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rp1_adc_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rp1_adc_data *data = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ hwmon_device_unregister(data->hwmon_dev);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id rp1_adc_dt_ids[] = {
|
||||
+ { .compatible = "raspberrypi,rp1-adc", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rp1_adc_dt_ids);
|
||||
+
|
||||
+static struct platform_driver rp1_adc_driver = {
|
||||
+ .remove = rp1_adc_remove,
|
||||
+ .driver = {
|
||||
+ .name = MODULE_NAME,
|
||||
+ .of_match_table = rp1_adc_dt_ids,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver_probe(rp1_adc_driver, rp1_adc_probe);
|
||||
+
|
||||
+MODULE_DESCRIPTION("RP1 ADC driver");
|
||||
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,69 @@
|
||||
From 0c7aeb96fd3ab68011ba6c24239c501190890308 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 8 Mar 2023 14:27:58 +0000
|
||||
Subject: [PATCH] mfd: bcm2835-pm: Add support for BCM2712
|
||||
|
||||
BCM2712 lacks the "asb" and "rpivid_asb" register ranges, but still
|
||||
requires the use of the bcm2835-power driver to reset the V3D block.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/mfd/bcm2835-pm.c | 28 +++++++++++++++++++---------
|
||||
1 file changed, 19 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/mfd/bcm2835-pm.c
|
||||
+++ b/drivers/mfd/bcm2835-pm.c
|
||||
@@ -69,12 +69,30 @@ static int bcm2835_pm_get_pdata(struct p
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const struct of_device_id bcm2835_pm_of_match[] = {
|
||||
+ { .compatible = "brcm,bcm2835-pm-wdt", },
|
||||
+ { .compatible = "brcm,bcm2835-pm", },
|
||||
+ { .compatible = "brcm,bcm2711-pm", },
|
||||
+ { .compatible = "brcm,bcm2712-pm", .data = (const void *)1},
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
|
||||
+
|
||||
static int bcm2835_pm_probe(struct platform_device *pdev)
|
||||
{
|
||||
+ const struct of_device_id *of_id;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm2835_pm *pm;
|
||||
+ bool is_2712;
|
||||
int ret;
|
||||
|
||||
+ of_id = of_match_node(bcm2835_pm_of_match, pdev->dev.of_node);
|
||||
+ if (!of_id) {
|
||||
+ dev_err(&pdev->dev, "Failed to match compatible string\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ is_2712 = !!of_id->data;
|
||||
+
|
||||
pm = devm_kzalloc(dev, sizeof(*pm), GFP_KERNEL);
|
||||
if (!pm)
|
||||
return -ENOMEM;
|
||||
@@ -97,21 +115,13 @@ static int bcm2835_pm_probe(struct platf
|
||||
* bcm2835-pm binding as the key for whether we can reference
|
||||
* the full PM register range and support power domains.
|
||||
*/
|
||||
- if (pm->asb)
|
||||
+ if (pm->asb || is_2712)
|
||||
return devm_mfd_add_devices(dev, -1, bcm2835_power_devs,
|
||||
ARRAY_SIZE(bcm2835_power_devs),
|
||||
NULL, 0, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static const struct of_device_id bcm2835_pm_of_match[] = {
|
||||
- { .compatible = "brcm,bcm2835-pm-wdt", },
|
||||
- { .compatible = "brcm,bcm2835-pm", },
|
||||
- { .compatible = "brcm,bcm2711-pm", },
|
||||
- {},
|
||||
-};
|
||||
-MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
|
||||
-
|
||||
static struct platform_driver bcm2835_pm_driver = {
|
||||
.probe = bcm2835_pm_probe,
|
||||
.driver = {
|
@ -0,0 +1,76 @@
|
||||
From 9cf85a95eeb239a079a3485bd1d0447431bdc7f1 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Wed, 8 Mar 2023 14:42:48 +0000
|
||||
Subject: [PATCH] soc: bcm: bcm2835-power: Add support for BCM2712
|
||||
|
||||
BCM2712 has a PM block but neither ASB nor RPIVID_ASB. Use the absence
|
||||
of the "asb" register range to indicate BCM2712 and its different PM
|
||||
register range.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/soc/bcm/bcm2835-power.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/soc/bcm/bcm2835-power.c
|
||||
+++ b/drivers/soc/bcm/bcm2835-power.c
|
||||
@@ -79,6 +79,7 @@
|
||||
#define PM_IMAGE 0x108
|
||||
#define PM_GRAFX 0x10c
|
||||
#define PM_PROC 0x110
|
||||
+#define PM_GRAFX_2712 0x304
|
||||
#define PM_ENAB BIT(12)
|
||||
#define PM_ISPRSTN BIT(8)
|
||||
#define PM_H264RSTN BIT(7)
|
||||
@@ -381,6 +382,9 @@ static int bcm2835_power_pd_power_on(str
|
||||
return bcm2835_power_power_on(pd, PM_GRAFX);
|
||||
|
||||
case BCM2835_POWER_DOMAIN_GRAFX_V3D:
|
||||
+ if (!power->asb)
|
||||
+ return bcm2835_asb_power_on(pd, PM_GRAFX_2712,
|
||||
+ 0, 0, PM_V3DRSTN);
|
||||
return bcm2835_asb_power_on(pd, PM_GRAFX,
|
||||
ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
|
||||
PM_V3DRSTN);
|
||||
@@ -447,6 +451,9 @@ static int bcm2835_power_pd_power_off(st
|
||||
return bcm2835_power_power_off(pd, PM_GRAFX);
|
||||
|
||||
case BCM2835_POWER_DOMAIN_GRAFX_V3D:
|
||||
+ if (!power->asb)
|
||||
+ return bcm2835_asb_power_off(pd, PM_GRAFX_2712,
|
||||
+ 0, 0, PM_V3DRSTN);
|
||||
return bcm2835_asb_power_off(pd, PM_GRAFX,
|
||||
ASB_V3D_M_CTRL, ASB_V3D_S_CTRL,
|
||||
PM_V3DRSTN);
|
||||
@@ -642,19 +649,21 @@ static int bcm2835_power_probe(struct pl
|
||||
power->asb = pm->asb;
|
||||
power->rpivid_asb = pm->rpivid_asb;
|
||||
|
||||
- id = readl(power->asb + ASB_AXI_BRDG_ID);
|
||||
- if (id != BCM2835_BRDG_ID /* "BRDG" */) {
|
||||
- dev_err(dev, "ASB register ID returned 0x%08x\n", id);
|
||||
- return -ENODEV;
|
||||
- }
|
||||
-
|
||||
- if (power->rpivid_asb) {
|
||||
- id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
|
||||
+ if (power->asb) {
|
||||
+ id = readl(power->asb + ASB_AXI_BRDG_ID);
|
||||
if (id != BCM2835_BRDG_ID /* "BRDG" */) {
|
||||
- dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
|
||||
- id);
|
||||
+ dev_err(dev, "ASB register ID returned 0x%08x\n", id);
|
||||
return -ENODEV;
|
||||
}
|
||||
+
|
||||
+ if (power->rpivid_asb) {
|
||||
+ id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID);
|
||||
+ if (id != BCM2835_BRDG_ID /* "BRDG" */) {
|
||||
+ dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n",
|
||||
+ id);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
power->pd_xlate.domains = devm_kcalloc(dev,
|
@ -0,0 +1,150 @@
|
||||
From 380c336af070edf85826abbb0057bf92a03ec466 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
|
||||
Date: Wed, 1 Mar 2023 17:57:11 +0000
|
||||
Subject: [PATCH] drivers: spi: Fix spi-gpio to correctly implement
|
||||
sck-idle-input
|
||||
|
||||
Formerly, if configured using DT, CS GPIOs were driven from spi.c
|
||||
and it was possible for CS to be asserted (low) *before* starting
|
||||
to drive SCK. CS GPIOs have been brought under control of this
|
||||
driver in both ACPI and DT cases, with a fixup for GPIO polarity.
|
||||
|
||||
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
|
||||
---
|
||||
drivers/spi/spi-gpio.c | 74 +++++++++++++++++++++++++++++-------------
|
||||
1 file changed, 51 insertions(+), 23 deletions(-)
|
||||
|
||||
--- a/drivers/spi/spi-gpio.c
|
||||
+++ b/drivers/spi/spi-gpio.c
|
||||
@@ -37,6 +37,7 @@ struct spi_gpio {
|
||||
struct gpio_desc *mosi;
|
||||
bool sck_idle_input;
|
||||
struct gpio_desc **cs_gpios;
|
||||
+ bool cs_dont_invert;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@@ -233,12 +234,18 @@ static void spi_gpio_chipselect(struct s
|
||||
gpiod_set_value_cansleep(spi_gpio->sck, spi->mode & SPI_CPOL);
|
||||
}
|
||||
|
||||
- /* Drive chip select line, if we have one */
|
||||
+ /*
|
||||
+ * Drive chip select line, if we have one.
|
||||
+ * SPI chip selects are normally active-low, but when
|
||||
+ * cs_dont_invert is set, we assume their polarity is
|
||||
+ * controlled by the GPIO, and write '1' to assert.
|
||||
+ */
|
||||
if (spi_gpio->cs_gpios) {
|
||||
struct gpio_desc *cs = spi_gpio->cs_gpios[spi->chip_select];
|
||||
+ int val = ((spi->mode & SPI_CS_HIGH) || spi_gpio->cs_dont_invert) ?
|
||||
+ is_active : !is_active;
|
||||
|
||||
- /* SPI chip selects are normally active-low */
|
||||
- gpiod_set_value_cansleep(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
|
||||
+ gpiod_set_value_cansleep(cs, val);
|
||||
}
|
||||
|
||||
if (spi_gpio->sck_idle_input && !is_active)
|
||||
@@ -254,12 +261,14 @@ static int spi_gpio_setup(struct spi_dev
|
||||
/*
|
||||
* The CS GPIOs have already been
|
||||
* initialized from the descriptor lookup.
|
||||
+ * Here we set them to the non-asserted state.
|
||||
*/
|
||||
if (spi_gpio->cs_gpios) {
|
||||
cs = spi_gpio->cs_gpios[spi->chip_select];
|
||||
if (!spi->controller_state && cs)
|
||||
status = gpiod_direction_output(cs,
|
||||
- !(spi->mode & SPI_CS_HIGH));
|
||||
+ !((spi->mode & SPI_CS_HIGH) ||
|
||||
+ spi_gpio->cs_dont_invert));
|
||||
}
|
||||
|
||||
if (!status)
|
||||
@@ -336,6 +345,38 @@ static int spi_gpio_request(struct devic
|
||||
return PTR_ERR_OR_ZERO(spi_gpio->sck);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * In order to implement "sck-idle-input" (which requires SCK
|
||||
+ * direction and CS level to be switched in a particular order),
|
||||
+ * we need to control GPIO chip selects from within this driver.
|
||||
+ */
|
||||
+
|
||||
+static int spi_gpio_probe_get_cs_gpios(struct device *dev,
|
||||
+ struct spi_master *master,
|
||||
+ bool gpio_defines_polarity)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct spi_gpio *spi_gpio = spi_master_get_devdata(master);
|
||||
+
|
||||
+ spi_gpio->cs_dont_invert = gpio_defines_polarity;
|
||||
+ spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect,
|
||||
+ sizeof(*spi_gpio->cs_gpios),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!spi_gpio->cs_gpios)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (i = 0; i < master->num_chipselect; i++) {
|
||||
+ spi_gpio->cs_gpios[i] =
|
||||
+ devm_gpiod_get_index(dev, "cs", i,
|
||||
+ gpio_defines_polarity ?
|
||||
+ GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
|
||||
+ if (IS_ERR(spi_gpio->cs_gpios[i]))
|
||||
+ return PTR_ERR(spi_gpio->cs_gpios[i]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id spi_gpio_dt_ids[] = {
|
||||
{ .compatible = "spi-gpio" },
|
||||
@@ -346,10 +387,12 @@ MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids)
|
||||
static int spi_gpio_probe_dt(struct platform_device *pdev,
|
||||
struct spi_master *master)
|
||||
{
|
||||
- master->dev.of_node = pdev->dev.of_node;
|
||||
- master->use_gpio_descriptors = true;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
|
||||
- return 0;
|
||||
+ master->dev.of_node = dev->of_node;
|
||||
+ master->num_chipselect = gpiod_count(dev, "cs");
|
||||
+
|
||||
+ return spi_gpio_probe_get_cs_gpios(dev, master, true);
|
||||
}
|
||||
#else
|
||||
static inline int spi_gpio_probe_dt(struct platform_device *pdev,
|
||||
@@ -364,8 +407,6 @@ static int spi_gpio_probe_pdata(struct p
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_gpio_platform_data *pdata = dev_get_platdata(dev);
|
||||
- struct spi_gpio *spi_gpio = spi_master_get_devdata(master);
|
||||
- int i;
|
||||
|
||||
#ifdef GENERIC_BITBANG
|
||||
if (!pdata || !pdata->num_chipselect)
|
||||
@@ -377,20 +418,7 @@ static int spi_gpio_probe_pdata(struct p
|
||||
*/
|
||||
master->num_chipselect = pdata->num_chipselect ?: 1;
|
||||
|
||||
- spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect,
|
||||
- sizeof(*spi_gpio->cs_gpios),
|
||||
- GFP_KERNEL);
|
||||
- if (!spi_gpio->cs_gpios)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- for (i = 0; i < master->num_chipselect; i++) {
|
||||
- spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", i,
|
||||
- GPIOD_OUT_HIGH);
|
||||
- if (IS_ERR(spi_gpio->cs_gpios[i]))
|
||||
- return PTR_ERR(spi_gpio->cs_gpios[i]);
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
+ return spi_gpio_probe_get_cs_gpios(dev, master, false);
|
||||
}
|
||||
|
||||
static int spi_gpio_probe(struct platform_device *pdev)
|
@ -0,0 +1,55 @@
|
||||
From 586f87307e75552292cfc6c76b81cd38d5ec31e2 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
|
||||
Date: Mon, 4 Sep 2023 10:57:47 +0100
|
||||
Subject: [PATCH] spi: spi-gpio: Implement spidelay when requested bit rate <=
|
||||
1 Mbps
|
||||
|
||||
Formerly the delay was omitted as bit-banged SPI seldom achieved
|
||||
even one Mbit/s; but some modern platforms can run faster, and
|
||||
some SPI devices may need to be clocked slower.
|
||||
|
||||
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
|
||||
---
|
||||
drivers/spi/spi-gpio.c | 18 ++++++++++++------
|
||||
1 file changed, 12 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/spi/spi-gpio.c
|
||||
+++ b/drivers/spi/spi-gpio.c
|
||||
@@ -11,12 +11,12 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
+#include <linux/delay.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/spi/spi_gpio.h>
|
||||
|
||||
-
|
||||
/*
|
||||
* This bitbanging SPI master driver should help make systems usable
|
||||
* when a native hardware SPI engine is not available, perhaps because
|
||||
@@ -111,12 +111,18 @@ static inline int getmiso(const struct s
|
||||
}
|
||||
|
||||
/*
|
||||
- * NOTE: this clocks "as fast as we can". It "should" be a function of the
|
||||
- * requested device clock. Software overhead means we usually have trouble
|
||||
- * reaching even one Mbit/sec (except when we can inline bitops), so for now
|
||||
- * we'll just assume we never need additional per-bit slowdowns.
|
||||
+ * Generic bit-banged GPIO SPI might free-run at something in the range
|
||||
+ * 1Mbps ~ 10Mbps (depending on the platform), and some SPI devices may
|
||||
+ * need to be clocked at a lower rate. ndelay() is often implemented by
|
||||
+ * udelay() with rounding up, so do the delay only for nsecs >= 500
|
||||
+ * (<= 1Mbps). The conditional test adds a small overhead.
|
||||
*/
|
||||
-#define spidelay(nsecs) do {} while (0)
|
||||
+
|
||||
+static inline void spidelay(unsigned long nsecs)
|
||||
+{
|
||||
+ if (nsecs >= 500)
|
||||
+ ndelay(nsecs);
|
||||
+}
|
||||
|
||||
#include "spi-bitbang-txrx.h"
|
||||
|
@ -0,0 +1,672 @@
|
||||
From 3f949caeef21269afc67dd62ae9826204f215934 Mon Sep 17 00:00:00 2001
|
||||
From: Iago Toral Quiroga <itoral@igalia.com>
|
||||
Date: Thu, 2 Mar 2023 11:49:46 +0100
|
||||
Subject: [PATCH] drm/v3d: fix up register addresses for V3D 7.x
|
||||
|
||||
v2: fix kernel panic with debug-fs interface to list registers
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_debugfs.c | 177 +++++++++++++++++-------------
|
||||
drivers/gpu/drm/v3d/v3d_gem.c | 3 +
|
||||
drivers/gpu/drm/v3d/v3d_irq.c | 47 ++++----
|
||||
drivers/gpu/drm/v3d/v3d_regs.h | 51 ++++++++-
|
||||
drivers/gpu/drm/v3d/v3d_sched.c | 41 ++++---
|
||||
5 files changed, 204 insertions(+), 115 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
|
||||
@@ -13,69 +13,83 @@
|
||||
#include "v3d_drv.h"
|
||||
#include "v3d_regs.h"
|
||||
|
||||
-#define REGDEF(reg) { reg, #reg }
|
||||
+#define REGDEF(min_ver, max_ver, reg) { min_ver, max_ver, reg, #reg }
|
||||
struct v3d_reg_def {
|
||||
+ u32 min_ver;
|
||||
+ u32 max_ver;
|
||||
u32 reg;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static const struct v3d_reg_def v3d_hub_reg_defs[] = {
|
||||
- REGDEF(V3D_HUB_AXICFG),
|
||||
- REGDEF(V3D_HUB_UIFCFG),
|
||||
- REGDEF(V3D_HUB_IDENT0),
|
||||
- REGDEF(V3D_HUB_IDENT1),
|
||||
- REGDEF(V3D_HUB_IDENT2),
|
||||
- REGDEF(V3D_HUB_IDENT3),
|
||||
- REGDEF(V3D_HUB_INT_STS),
|
||||
- REGDEF(V3D_HUB_INT_MSK_STS),
|
||||
-
|
||||
- REGDEF(V3D_MMU_CTL),
|
||||
- REGDEF(V3D_MMU_VIO_ADDR),
|
||||
- REGDEF(V3D_MMU_VIO_ID),
|
||||
- REGDEF(V3D_MMU_DEBUG_INFO),
|
||||
+ REGDEF(33, 42, V3D_HUB_AXICFG),
|
||||
+ REGDEF(33, 71, V3D_HUB_UIFCFG),
|
||||
+ REGDEF(33, 71, V3D_HUB_IDENT0),
|
||||
+ REGDEF(33, 71, V3D_HUB_IDENT1),
|
||||
+ REGDEF(33, 71, V3D_HUB_IDENT2),
|
||||
+ REGDEF(33, 71, V3D_HUB_IDENT3),
|
||||
+ REGDEF(33, 71, V3D_HUB_INT_STS),
|
||||
+ REGDEF(33, 71, V3D_HUB_INT_MSK_STS),
|
||||
+
|
||||
+ REGDEF(33, 71, V3D_MMU_CTL),
|
||||
+ REGDEF(33, 71, V3D_MMU_VIO_ADDR),
|
||||
+ REGDEF(33, 71, V3D_MMU_VIO_ID),
|
||||
+ REGDEF(33, 71, V3D_MMU_DEBUG_INFO),
|
||||
+
|
||||
+ REGDEF(71, 71, V3D_V7_GMP_STATUS),
|
||||
+ REGDEF(71, 71, V3D_V7_GMP_CFG),
|
||||
+ REGDEF(71, 71, V3D_V7_GMP_VIO_ADDR),
|
||||
};
|
||||
|
||||
static const struct v3d_reg_def v3d_gca_reg_defs[] = {
|
||||
- REGDEF(V3D_GCA_SAFE_SHUTDOWN),
|
||||
- REGDEF(V3D_GCA_SAFE_SHUTDOWN_ACK),
|
||||
+ REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN),
|
||||
+ REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK),
|
||||
};
|
||||
|
||||
static const struct v3d_reg_def v3d_core_reg_defs[] = {
|
||||
- REGDEF(V3D_CTL_IDENT0),
|
||||
- REGDEF(V3D_CTL_IDENT1),
|
||||
- REGDEF(V3D_CTL_IDENT2),
|
||||
- REGDEF(V3D_CTL_MISCCFG),
|
||||
- REGDEF(V3D_CTL_INT_STS),
|
||||
- REGDEF(V3D_CTL_INT_MSK_STS),
|
||||
- REGDEF(V3D_CLE_CT0CS),
|
||||
- REGDEF(V3D_CLE_CT0CA),
|
||||
- REGDEF(V3D_CLE_CT0EA),
|
||||
- REGDEF(V3D_CLE_CT1CS),
|
||||
- REGDEF(V3D_CLE_CT1CA),
|
||||
- REGDEF(V3D_CLE_CT1EA),
|
||||
-
|
||||
- REGDEF(V3D_PTB_BPCA),
|
||||
- REGDEF(V3D_PTB_BPCS),
|
||||
-
|
||||
- REGDEF(V3D_GMP_STATUS),
|
||||
- REGDEF(V3D_GMP_CFG),
|
||||
- REGDEF(V3D_GMP_VIO_ADDR),
|
||||
-
|
||||
- REGDEF(V3D_ERR_FDBGO),
|
||||
- REGDEF(V3D_ERR_FDBGB),
|
||||
- REGDEF(V3D_ERR_FDBGS),
|
||||
- REGDEF(V3D_ERR_STAT),
|
||||
+ REGDEF(33, 71, V3D_CTL_IDENT0),
|
||||
+ REGDEF(33, 71, V3D_CTL_IDENT1),
|
||||
+ REGDEF(33, 71, V3D_CTL_IDENT2),
|
||||
+ REGDEF(33, 71, V3D_CTL_MISCCFG),
|
||||
+ REGDEF(33, 71, V3D_CTL_INT_STS),
|
||||
+ REGDEF(33, 71, V3D_CTL_INT_MSK_STS),
|
||||
+ REGDEF(33, 71, V3D_CLE_CT0CS),
|
||||
+ REGDEF(33, 71, V3D_CLE_CT0CA),
|
||||
+ REGDEF(33, 71, V3D_CLE_CT0EA),
|
||||
+ REGDEF(33, 71, V3D_CLE_CT1CS),
|
||||
+ REGDEF(33, 71, V3D_CLE_CT1CA),
|
||||
+ REGDEF(33, 71, V3D_CLE_CT1EA),
|
||||
+
|
||||
+ REGDEF(33, 71, V3D_PTB_BPCA),
|
||||
+ REGDEF(33, 71, V3D_PTB_BPCS),
|
||||
+
|
||||
+ REGDEF(33, 41, V3D_GMP_STATUS),
|
||||
+ REGDEF(33, 41, V3D_GMP_CFG),
|
||||
+ REGDEF(33, 41, V3D_GMP_VIO_ADDR),
|
||||
+
|
||||
+ REGDEF(33, 71, V3D_ERR_FDBGO),
|
||||
+ REGDEF(33, 71, V3D_ERR_FDBGB),
|
||||
+ REGDEF(33, 71, V3D_ERR_FDBGS),
|
||||
+ REGDEF(33, 71, V3D_ERR_STAT),
|
||||
};
|
||||
|
||||
static const struct v3d_reg_def v3d_csd_reg_defs[] = {
|
||||
- REGDEF(V3D_CSD_STATUS),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG0),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG1),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG2),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG3),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG4),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG5),
|
||||
- REGDEF(V3D_CSD_CURRENT_CFG6),
|
||||
+ REGDEF(41, 71, V3D_CSD_STATUS),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG0),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG1),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG2),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG3),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG4),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG5),
|
||||
+ REGDEF(41, 41, V3D_CSD_CURRENT_CFG6),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG0),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG1),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG2),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG3),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG4),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG5),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG6),
|
||||
+ REGDEF(71, 71, V3D_V7_CSD_CURRENT_CFG7),
|
||||
};
|
||||
|
||||
static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
|
||||
@@ -86,38 +100,41 @@ static int v3d_v3d_debugfs_regs(struct s
|
||||
int i, core;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(v3d_hub_reg_defs); i++) {
|
||||
- seq_printf(m, "%s (0x%04x): 0x%08x\n",
|
||||
- v3d_hub_reg_defs[i].name, v3d_hub_reg_defs[i].reg,
|
||||
- V3D_READ(v3d_hub_reg_defs[i].reg));
|
||||
+ const struct v3d_reg_def *def = &v3d_hub_reg_defs[i];
|
||||
+
|
||||
+ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
|
||||
+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
|
||||
+ def->name, def->reg, V3D_READ(def->reg));
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (v3d->ver < 41) {
|
||||
- for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(v3d_gca_reg_defs); i++) {
|
||||
+ const struct v3d_reg_def *def = &v3d_gca_reg_defs[i];
|
||||
+
|
||||
+ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
|
||||
seq_printf(m, "%s (0x%04x): 0x%08x\n",
|
||||
- v3d_gca_reg_defs[i].name,
|
||||
- v3d_gca_reg_defs[i].reg,
|
||||
- V3D_GCA_READ(v3d_gca_reg_defs[i].reg));
|
||||
+ def->name, def->reg, V3D_GCA_READ(def->reg));
|
||||
}
|
||||
}
|
||||
|
||||
for (core = 0; core < v3d->cores; core++) {
|
||||
for (i = 0; i < ARRAY_SIZE(v3d_core_reg_defs); i++) {
|
||||
- seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
|
||||
- core,
|
||||
- v3d_core_reg_defs[i].name,
|
||||
- v3d_core_reg_defs[i].reg,
|
||||
- V3D_CORE_READ(core,
|
||||
- v3d_core_reg_defs[i].reg));
|
||||
+ const struct v3d_reg_def *def = &v3d_core_reg_defs[i];
|
||||
+
|
||||
+ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
|
||||
+ seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
|
||||
+ core, def->name, def->reg,
|
||||
+ V3D_CORE_READ(core, def->reg));
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (v3d_has_csd(v3d)) {
|
||||
- for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(v3d_csd_reg_defs); i++) {
|
||||
+ const struct v3d_reg_def *def = &v3d_csd_reg_defs[i];
|
||||
+
|
||||
+ if (v3d->ver >= def->min_ver && v3d->ver <= def->max_ver) {
|
||||
seq_printf(m, "core %d %s (0x%04x): 0x%08x\n",
|
||||
- core,
|
||||
- v3d_csd_reg_defs[i].name,
|
||||
- v3d_csd_reg_defs[i].reg,
|
||||
- V3D_CORE_READ(core,
|
||||
- v3d_csd_reg_defs[i].reg));
|
||||
+ core, def->name, def->reg,
|
||||
+ V3D_CORE_READ(core, def->reg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,8 +165,10 @@ static int v3d_v3d_debugfs_ident(struct
|
||||
str_yes_no(ident2 & V3D_HUB_IDENT2_WITH_MMU));
|
||||
seq_printf(m, "TFU: %s\n",
|
||||
str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TFU));
|
||||
- seq_printf(m, "TSY: %s\n",
|
||||
- str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY));
|
||||
+ if (v3d->ver <= 42) {
|
||||
+ seq_printf(m, "TSY: %s\n",
|
||||
+ str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY));
|
||||
+ }
|
||||
seq_printf(m, "MSO: %s\n",
|
||||
str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_MSO));
|
||||
seq_printf(m, "L3C: %s (%dkb)\n",
|
||||
@@ -178,10 +197,14 @@ static int v3d_v3d_debugfs_ident(struct
|
||||
seq_printf(m, " QPUs: %d\n", nslc * qups);
|
||||
seq_printf(m, " Semaphores: %d\n",
|
||||
V3D_GET_FIELD(ident1, V3D_IDENT1_NSEM));
|
||||
- seq_printf(m, " BCG int: %d\n",
|
||||
- (ident2 & V3D_IDENT2_BCG_INT) != 0);
|
||||
- seq_printf(m, " Override TMU: %d\n",
|
||||
- (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
|
||||
+ if (v3d->ver <= 42) {
|
||||
+ seq_printf(m, " BCG int: %d\n",
|
||||
+ (ident2 & V3D_IDENT2_BCG_INT) != 0);
|
||||
+ }
|
||||
+ if (v3d->ver < 40) {
|
||||
+ seq_printf(m, " Override TMU: %d\n",
|
||||
+ (misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -289,8 +312,10 @@ static int v3d_measure_clock(struct seq_
|
||||
int measure_ms = 1000;
|
||||
|
||||
if (v3d->ver >= 40) {
|
||||
+ int cycle_count_reg = v3d->ver < 71 ?
|
||||
+ V3D_PCTR_CYCLE_COUNT : V3D_V7_PCTR_CYCLE_COUNT;
|
||||
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
|
||||
- V3D_SET_FIELD(V3D_PCTR_CYCLE_COUNT,
|
||||
+ V3D_SET_FIELD(cycle_count_reg,
|
||||
V3D_PCTR_S0));
|
||||
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
|
||||
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
|
||||
--- a/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
|
||||
@@ -88,6 +88,9 @@ v3d_init_hw_state(struct v3d_dev *v3d)
|
||||
static void
|
||||
v3d_idle_axi(struct v3d_dev *v3d, int core)
|
||||
{
|
||||
+ if (v3d->ver >= 71)
|
||||
+ return;
|
||||
+
|
||||
V3D_CORE_WRITE(core, V3D_GMP_CFG, V3D_GMP_CFG_STOP_REQ);
|
||||
|
||||
if (wait_for((V3D_CORE_READ(core, V3D_GMP_STATUS) &
|
||||
--- a/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
|
||||
@@ -20,16 +20,17 @@
|
||||
#include "v3d_regs.h"
|
||||
#include "v3d_trace.h"
|
||||
|
||||
-#define V3D_CORE_IRQS ((u32)(V3D_INT_OUTOMEM | \
|
||||
- V3D_INT_FLDONE | \
|
||||
- V3D_INT_FRDONE | \
|
||||
- V3D_INT_CSDDONE | \
|
||||
- V3D_INT_GMPV))
|
||||
-
|
||||
-#define V3D_HUB_IRQS ((u32)(V3D_HUB_INT_MMU_WRV | \
|
||||
- V3D_HUB_INT_MMU_PTI | \
|
||||
- V3D_HUB_INT_MMU_CAP | \
|
||||
- V3D_HUB_INT_TFUC))
|
||||
+#define V3D_CORE_IRQS(ver) ((u32)(V3D_INT_OUTOMEM | \
|
||||
+ V3D_INT_FLDONE | \
|
||||
+ V3D_INT_FRDONE | \
|
||||
+ (ver < 71 ? V3D_INT_CSDDONE : V3D_V7_INT_CSDDONE) | \
|
||||
+ (ver < 71 ? V3D_INT_GMPV : 0)))
|
||||
+
|
||||
+#define V3D_HUB_IRQS(ver) ((u32)(V3D_HUB_INT_MMU_WRV | \
|
||||
+ V3D_HUB_INT_MMU_PTI | \
|
||||
+ V3D_HUB_INT_MMU_CAP | \
|
||||
+ V3D_HUB_INT_TFUC | \
|
||||
+ (ver >= 71 ? V3D_V7_HUB_INT_GMPV : 0)))
|
||||
|
||||
static irqreturn_t
|
||||
v3d_hub_irq(int irq, void *arg);
|
||||
@@ -118,7 +119,8 @@ v3d_irq(int irq, void *arg)
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
- if (intsts & V3D_INT_CSDDONE) {
|
||||
+ if ((v3d->ver < 71 && (intsts & V3D_INT_CSDDONE)) ||
|
||||
+ (v3d->ver >= 71 && (intsts & V3D_V7_INT_CSDDONE))) {
|
||||
struct v3d_fence *fence =
|
||||
to_v3d_fence(v3d->csd_job->base.irq_fence);
|
||||
v3d->gpu_queue_stats[V3D_CSD].last_exec_end = local_clock();
|
||||
@@ -131,7 +133,7 @@ v3d_irq(int irq, void *arg)
|
||||
/* We shouldn't be triggering these if we have GMP in
|
||||
* always-allowed mode.
|
||||
*/
|
||||
- if (intsts & V3D_INT_GMPV)
|
||||
+ if (v3d->ver < 71 && (intsts & V3D_INT_GMPV))
|
||||
dev_err(v3d->drm.dev, "GMP violation\n");
|
||||
|
||||
/* V3D 4.2 wires the hub and core IRQs together, so if we &
|
||||
@@ -205,6 +207,11 @@ v3d_hub_irq(int irq, void *arg)
|
||||
status = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+ if (v3d->ver >= 71 && intsts & V3D_V7_HUB_INT_GMPV) {
|
||||
+ dev_err(v3d->drm.dev, "GMP Violation\n");
|
||||
+ status = IRQ_HANDLED;
|
||||
+ }
|
||||
+
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -219,8 +226,8 @@ v3d_irq_init(struct v3d_dev *v3d)
|
||||
* for us.
|
||||
*/
|
||||
for (core = 0; core < v3d->cores; core++)
|
||||
- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
|
||||
- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver));
|
||||
+ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver));
|
||||
|
||||
irq1 = platform_get_irq_optional(v3d_to_pdev(v3d), 1);
|
||||
if (irq1 == -EPROBE_DEFER)
|
||||
@@ -264,12 +271,12 @@ v3d_irq_enable(struct v3d_dev *v3d)
|
||||
|
||||
/* Enable our set of interrupts, masking out any others. */
|
||||
for (core = 0; core < v3d->cores; core++) {
|
||||
- V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS);
|
||||
- V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS);
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_SET, ~V3D_CORE_IRQS(v3d->ver));
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_INT_MSK_CLR, V3D_CORE_IRQS(v3d->ver));
|
||||
}
|
||||
|
||||
- V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS);
|
||||
- V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS);
|
||||
+ V3D_WRITE(V3D_HUB_INT_MSK_SET, ~V3D_HUB_IRQS(v3d->ver));
|
||||
+ V3D_WRITE(V3D_HUB_INT_MSK_CLR, V3D_HUB_IRQS(v3d->ver));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -284,8 +291,8 @@ v3d_irq_disable(struct v3d_dev *v3d)
|
||||
|
||||
/* Clear any pending interrupts we might have left. */
|
||||
for (core = 0; core < v3d->cores; core++)
|
||||
- V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS);
|
||||
- V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS);
|
||||
+ V3D_CORE_WRITE(core, V3D_CTL_INT_CLR, V3D_CORE_IRQS(v3d->ver));
|
||||
+ V3D_WRITE(V3D_HUB_INT_CLR, V3D_HUB_IRQS(v3d->ver));
|
||||
|
||||
cancel_work_sync(&v3d->overflow_mem_work);
|
||||
}
|
||||
--- a/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
|
||||
@@ -57,6 +57,7 @@
|
||||
#define V3D_HUB_INT_MSK_STS 0x0005c
|
||||
#define V3D_HUB_INT_MSK_SET 0x00060
|
||||
#define V3D_HUB_INT_MSK_CLR 0x00064
|
||||
+# define V3D_V7_HUB_INT_GMPV BIT(6)
|
||||
# define V3D_HUB_INT_MMU_WRV BIT(5)
|
||||
# define V3D_HUB_INT_MMU_PTI BIT(4)
|
||||
# define V3D_HUB_INT_MMU_CAP BIT(3)
|
||||
@@ -64,6 +65,7 @@
|
||||
# define V3D_HUB_INT_TFUC BIT(1)
|
||||
# define V3D_HUB_INT_TFUF BIT(0)
|
||||
|
||||
+/* GCA registers only exist in V3D < 41 */
|
||||
#define V3D_GCA_CACHE_CTRL 0x0000c
|
||||
# define V3D_GCA_CACHE_CTRL_FLUSH BIT(0)
|
||||
|
||||
@@ -87,6 +89,7 @@
|
||||
# define V3D_TOP_GR_BRIDGE_SW_INIT_1_V3D_CLK_108_SW_INIT BIT(0)
|
||||
|
||||
#define V3D_TFU_CS 0x00400
|
||||
+#define V3D_V7_TFU_CS 0x00700
|
||||
/* Stops current job, empties input fifo. */
|
||||
# define V3D_TFU_CS_TFURST BIT(31)
|
||||
# define V3D_TFU_CS_CVTCT_MASK V3D_MASK(23, 16)
|
||||
@@ -96,6 +99,7 @@
|
||||
# define V3D_TFU_CS_BUSY BIT(0)
|
||||
|
||||
#define V3D_TFU_SU 0x00404
|
||||
+#define V3D_V7_TFU_SU 0x00704
|
||||
/* Interrupt when FINTTHR input slots are free (0 = disabled) */
|
||||
# define V3D_TFU_SU_FINTTHR_MASK V3D_MASK(13, 8)
|
||||
# define V3D_TFU_SU_FINTTHR_SHIFT 8
|
||||
@@ -107,38 +111,53 @@
|
||||
# define V3D_TFU_SU_THROTTLE_SHIFT 0
|
||||
|
||||
#define V3D_TFU_ICFG 0x00408
|
||||
+#define V3D_V7_TFU_ICFG 0x00708
|
||||
/* Interrupt when the conversion is complete. */
|
||||
# define V3D_TFU_ICFG_IOC BIT(0)
|
||||
|
||||
/* Input Image Address */
|
||||
#define V3D_TFU_IIA 0x0040c
|
||||
+#define V3D_V7_TFU_IIA 0x0070c
|
||||
/* Input Chroma Address */
|
||||
#define V3D_TFU_ICA 0x00410
|
||||
+#define V3D_V7_TFU_ICA 0x00710
|
||||
/* Input Image Stride */
|
||||
#define V3D_TFU_IIS 0x00414
|
||||
+#define V3D_V7_TFU_IIS 0x00714
|
||||
/* Input Image U-Plane Address */
|
||||
#define V3D_TFU_IUA 0x00418
|
||||
+#define V3D_V7_TFU_IUA 0x00718
|
||||
+/* Image output config (VD 7.x only) */
|
||||
+#define V3D_V7_TFU_IOC 0x0071c
|
||||
/* Output Image Address */
|
||||
#define V3D_TFU_IOA 0x0041c
|
||||
+#define V3D_V7_TFU_IOA 0x00720
|
||||
/* Image Output Size */
|
||||
#define V3D_TFU_IOS 0x00420
|
||||
+#define V3D_V7_TFU_IOS 0x00724
|
||||
/* TFU YUV Coefficient 0 */
|
||||
#define V3D_TFU_COEF0 0x00424
|
||||
-/* Use these regs instead of the defaults. */
|
||||
+#define V3D_V7_TFU_COEF0 0x00728
|
||||
+/* Use these regs instead of the defaults (V3D 4.x only) */
|
||||
# define V3D_TFU_COEF0_USECOEF BIT(31)
|
||||
/* TFU YUV Coefficient 1 */
|
||||
#define V3D_TFU_COEF1 0x00428
|
||||
+#define V3D_V7_TFU_COEF1 0x0072c
|
||||
/* TFU YUV Coefficient 2 */
|
||||
#define V3D_TFU_COEF2 0x0042c
|
||||
+#define V3D_V7_TFU_COEF2 0x00730
|
||||
/* TFU YUV Coefficient 3 */
|
||||
#define V3D_TFU_COEF3 0x00430
|
||||
+#define V3D_V7_TFU_COEF3 0x00734
|
||||
|
||||
+/* V3D 4.x only */
|
||||
#define V3D_TFU_CRC 0x00434
|
||||
|
||||
/* Per-MMU registers. */
|
||||
|
||||
#define V3D_MMUC_CONTROL 0x01000
|
||||
# define V3D_MMUC_CONTROL_CLEAR BIT(3)
|
||||
+# define V3D_V7_MMUC_CONTROL_CLEAR BIT(11)
|
||||
# define V3D_MMUC_CONTROL_FLUSHING BIT(2)
|
||||
# define V3D_MMUC_CONTROL_FLUSH BIT(1)
|
||||
# define V3D_MMUC_CONTROL_ENABLE BIT(0)
|
||||
@@ -246,7 +265,6 @@
|
||||
|
||||
#define V3D_CTL_L2TCACTL 0x00030
|
||||
# define V3D_L2TCACTL_TMUWCF BIT(8)
|
||||
-# define V3D_L2TCACTL_L2T_NO_WM BIT(4)
|
||||
/* Invalidates cache lines. */
|
||||
# define V3D_L2TCACTL_FLM_FLUSH 0
|
||||
/* Removes cachelines without writing dirty lines back. */
|
||||
@@ -268,7 +286,9 @@
|
||||
# define V3D_INT_QPU_MASK V3D_MASK(27, 16)
|
||||
# define V3D_INT_QPU_SHIFT 16
|
||||
# define V3D_INT_CSDDONE BIT(7)
|
||||
+# define V3D_V7_INT_CSDDONE BIT(6)
|
||||
# define V3D_INT_PCTR BIT(6)
|
||||
+# define V3D_V7_INT_PCTR BIT(5)
|
||||
# define V3D_INT_GMPV BIT(5)
|
||||
# define V3D_INT_TRFB BIT(4)
|
||||
# define V3D_INT_SPILLUSE BIT(3)
|
||||
@@ -350,14 +370,19 @@
|
||||
#define V3D_V4_PCTR_0_SRC_X(x) (V3D_V4_PCTR_0_SRC_0_3 + \
|
||||
4 * (x))
|
||||
# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
|
||||
+# define V3D_V7_PCTR_S0_MASK V3D_MASK(7, 0)
|
||||
# define V3D_PCTR_S0_SHIFT 0
|
||||
# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)
|
||||
+# define V3D_V7_PCTR_S1_MASK V3D_MASK(15, 8)
|
||||
# define V3D_PCTR_S1_SHIFT 8
|
||||
# define V3D_PCTR_S2_MASK V3D_MASK(22, 16)
|
||||
+# define V3D_V7_PCTR_S2_MASK V3D_MASK(23, 16)
|
||||
# define V3D_PCTR_S2_SHIFT 16
|
||||
# define V3D_PCTR_S3_MASK V3D_MASK(30, 24)
|
||||
+# define V3D_V7_PCTR_S3_MASK V3D_MASK(31, 24)
|
||||
# define V3D_PCTR_S3_SHIFT 24
|
||||
# define V3D_PCTR_CYCLE_COUNT 32
|
||||
+# define V3D_V7_PCTR_CYCLE_COUNT 0
|
||||
|
||||
/* Output values of the counters. */
|
||||
#define V3D_PCTR_0_PCTR0 0x00680
|
||||
@@ -365,6 +390,7 @@
|
||||
#define V3D_PCTR_0_PCTRX(x) (V3D_PCTR_0_PCTR0 + \
|
||||
4 * (x))
|
||||
#define V3D_GMP_STATUS 0x00800
|
||||
+#define V3D_V7_GMP_STATUS 0x00600
|
||||
# define V3D_GMP_STATUS_GMPRST BIT(31)
|
||||
# define V3D_GMP_STATUS_WR_COUNT_MASK V3D_MASK(30, 24)
|
||||
# define V3D_GMP_STATUS_WR_COUNT_SHIFT 24
|
||||
@@ -378,12 +404,14 @@
|
||||
# define V3D_GMP_STATUS_VIO BIT(0)
|
||||
|
||||
#define V3D_GMP_CFG 0x00804
|
||||
+#define V3D_V7_GMP_CFG 0x00604
|
||||
# define V3D_GMP_CFG_LBURSTEN BIT(3)
|
||||
# define V3D_GMP_CFG_PGCRSEN BIT()
|
||||
# define V3D_GMP_CFG_STOP_REQ BIT(1)
|
||||
# define V3D_GMP_CFG_PROT_ENABLE BIT(0)
|
||||
|
||||
#define V3D_GMP_VIO_ADDR 0x00808
|
||||
+#define V3D_V7_GMP_VIO_ADDR 0x00608
|
||||
#define V3D_GMP_VIO_TYPE 0x0080c
|
||||
#define V3D_GMP_TABLE_ADDR 0x00810
|
||||
#define V3D_GMP_CLEAR_LOAD 0x00814
|
||||
@@ -399,24 +427,28 @@
|
||||
# define V3D_CSD_STATUS_HAVE_QUEUED_DISPATCH BIT(0)
|
||||
|
||||
#define V3D_CSD_QUEUED_CFG0 0x00904
|
||||
+#define V3D_V7_CSD_QUEUED_CFG0 0x00930
|
||||
# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_MASK V3D_MASK(31, 16)
|
||||
# define V3D_CSD_QUEUED_CFG0_NUM_WGS_X_SHIFT 16
|
||||
# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_MASK V3D_MASK(15, 0)
|
||||
# define V3D_CSD_QUEUED_CFG0_WG_X_OFFSET_SHIFT 0
|
||||
|
||||
#define V3D_CSD_QUEUED_CFG1 0x00908
|
||||
+#define V3D_V7_CSD_QUEUED_CFG1 0x00934
|
||||
# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_MASK V3D_MASK(31, 16)
|
||||
# define V3D_CSD_QUEUED_CFG1_NUM_WGS_Y_SHIFT 16
|
||||
# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_MASK V3D_MASK(15, 0)
|
||||
# define V3D_CSD_QUEUED_CFG1_WG_Y_OFFSET_SHIFT 0
|
||||
|
||||
#define V3D_CSD_QUEUED_CFG2 0x0090c
|
||||
+#define V3D_V7_CSD_QUEUED_CFG2 0x00938
|
||||
# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_MASK V3D_MASK(31, 16)
|
||||
# define V3D_CSD_QUEUED_CFG2_NUM_WGS_Z_SHIFT 16
|
||||
# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_MASK V3D_MASK(15, 0)
|
||||
# define V3D_CSD_QUEUED_CFG2_WG_Z_OFFSET_SHIFT 0
|
||||
|
||||
#define V3D_CSD_QUEUED_CFG3 0x00910
|
||||
+#define V3D_V7_CSD_QUEUED_CFG3 0x0093c
|
||||
# define V3D_CSD_QUEUED_CFG3_OVERLAP_WITH_PREV BIT(26)
|
||||
# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_MASK V3D_MASK(25, 20)
|
||||
# define V3D_CSD_QUEUED_CFG3_MAX_SG_ID_SHIFT 20
|
||||
@@ -429,22 +461,36 @@
|
||||
|
||||
/* Number of batches, minus 1 */
|
||||
#define V3D_CSD_QUEUED_CFG4 0x00914
|
||||
+#define V3D_V7_CSD_QUEUED_CFG4 0x00940
|
||||
|
||||
/* Shader address, pnan, singleseg, threading, like a shader record. */
|
||||
#define V3D_CSD_QUEUED_CFG5 0x00918
|
||||
+#define V3D_V7_CSD_QUEUED_CFG5 0x00944
|
||||
|
||||
/* Uniforms address (4 byte aligned) */
|
||||
#define V3D_CSD_QUEUED_CFG6 0x0091c
|
||||
+#define V3D_V7_CSD_QUEUED_CFG6 0x00948
|
||||
+
|
||||
+#define V3D_V7_CSD_QUEUED_CFG7 0x0094c
|
||||
|
||||
#define V3D_CSD_CURRENT_CFG0 0x00920
|
||||
+#define V3D_V7_CSD_CURRENT_CFG0 0x00958
|
||||
#define V3D_CSD_CURRENT_CFG1 0x00924
|
||||
+#define V3D_V7_CSD_CURRENT_CFG1 0x0095c
|
||||
#define V3D_CSD_CURRENT_CFG2 0x00928
|
||||
+#define V3D_V7_CSD_CURRENT_CFG2 0x00960
|
||||
#define V3D_CSD_CURRENT_CFG3 0x0092c
|
||||
+#define V3D_V7_CSD_CURRENT_CFG3 0x00964
|
||||
#define V3D_CSD_CURRENT_CFG4 0x00930
|
||||
+#define V3D_V7_CSD_CURRENT_CFG4 0x00968
|
||||
#define V3D_CSD_CURRENT_CFG5 0x00934
|
||||
+#define V3D_V7_CSD_CURRENT_CFG5 0x0096c
|
||||
#define V3D_CSD_CURRENT_CFG6 0x00938
|
||||
+#define V3D_V7_CSD_CURRENT_CFG6 0x00970
|
||||
+#define V3D_V7_CSD_CURRENT_CFG7 0x00974
|
||||
|
||||
#define V3D_CSD_CURRENT_ID0 0x0093c
|
||||
+#define V3D_V7_CSD_CURRENT_ID0 0x00978
|
||||
# define V3D_CSD_CURRENT_ID0_WG_X_MASK V3D_MASK(31, 16)
|
||||
# define V3D_CSD_CURRENT_ID0_WG_X_SHIFT 16
|
||||
# define V3D_CSD_CURRENT_ID0_WG_IN_SG_MASK V3D_MASK(11, 8)
|
||||
@@ -453,6 +499,7 @@
|
||||
# define V3D_CSD_CURRENT_ID0_L_IDX_SHIFT 0
|
||||
|
||||
#define V3D_CSD_CURRENT_ID1 0x00940
|
||||
+#define V3D_V7_CSD_CURRENT_ID1 0x0097c
|
||||
# define V3D_CSD_CURRENT_ID0_WG_Z_MASK V3D_MASK(31, 16)
|
||||
# define V3D_CSD_CURRENT_ID0_WG_Z_SHIFT 16
|
||||
# define V3D_CSD_CURRENT_ID0_WG_Y_MASK V3D_MASK(15, 0)
|
||||
--- a/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
|
||||
@@ -282,6 +282,8 @@ static struct dma_fence *v3d_render_job_
|
||||
return fence;
|
||||
}
|
||||
|
||||
+#define V3D_TFU_REG(name) ((v3d->ver < 71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name)
|
||||
+
|
||||
static struct dma_fence *
|
||||
v3d_tfu_job_run(struct drm_sched_job *sched_job)
|
||||
{
|
||||
@@ -302,20 +304,22 @@ v3d_tfu_job_run(struct drm_sched_job *sc
|
||||
trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
|
||||
|
||||
v3d_sched_stats_add_job(&v3d->gpu_queue_stats[V3D_TFU], sched_job);
|
||||
- V3D_WRITE(V3D_TFU_IIA, job->args.iia);
|
||||
- V3D_WRITE(V3D_TFU_IIS, job->args.iis);
|
||||
- V3D_WRITE(V3D_TFU_ICA, job->args.ica);
|
||||
- V3D_WRITE(V3D_TFU_IUA, job->args.iua);
|
||||
- V3D_WRITE(V3D_TFU_IOA, job->args.ioa);
|
||||
- V3D_WRITE(V3D_TFU_IOS, job->args.ios);
|
||||
- V3D_WRITE(V3D_TFU_COEF0, job->args.coef[0]);
|
||||
- if (job->args.coef[0] & V3D_TFU_COEF0_USECOEF) {
|
||||
- V3D_WRITE(V3D_TFU_COEF1, job->args.coef[1]);
|
||||
- V3D_WRITE(V3D_TFU_COEF2, job->args.coef[2]);
|
||||
- V3D_WRITE(V3D_TFU_COEF3, job->args.coef[3]);
|
||||
+ V3D_WRITE(V3D_TFU_REG(IIA), job->args.iia);
|
||||
+ V3D_WRITE(V3D_TFU_REG(IIS), job->args.iis);
|
||||
+ V3D_WRITE(V3D_TFU_REG(ICA), job->args.ica);
|
||||
+ V3D_WRITE(V3D_TFU_REG(IUA), job->args.iua);
|
||||
+ V3D_WRITE(V3D_TFU_REG(IOA), job->args.ioa);
|
||||
+ if (v3d->ver >= 71)
|
||||
+ V3D_WRITE(V3D_V7_TFU_IOC, job->args.v71.ioc);
|
||||
+ V3D_WRITE(V3D_TFU_REG(IOS), job->args.ios);
|
||||
+ V3D_WRITE(V3D_TFU_REG(COEF0), job->args.coef[0]);
|
||||
+ if (v3d->ver >= 71 || (job->args.coef[0] & V3D_TFU_COEF0_USECOEF)) {
|
||||
+ V3D_WRITE(V3D_TFU_REG(COEF1), job->args.coef[1]);
|
||||
+ V3D_WRITE(V3D_TFU_REG(COEF2), job->args.coef[2]);
|
||||
+ V3D_WRITE(V3D_TFU_REG(COEF3), job->args.coef[3]);
|
||||
}
|
||||
/* ICFG kicks off the job. */
|
||||
- V3D_WRITE(V3D_TFU_ICFG, job->args.icfg | V3D_TFU_ICFG_IOC);
|
||||
+ V3D_WRITE(V3D_TFU_REG(ICFG), job->args.icfg | V3D_TFU_ICFG_IOC);
|
||||
|
||||
return fence;
|
||||
}
|
||||
@@ -327,7 +331,7 @@ v3d_csd_job_run(struct drm_sched_job *sc
|
||||
struct v3d_dev *v3d = job->base.v3d;
|
||||
struct drm_device *dev = &v3d->drm;
|
||||
struct dma_fence *fence;
|
||||
- int i;
|
||||
+ int i, csd_cfg0_reg, csd_cfg_reg_count;
|
||||
|
||||
v3d->csd_job = job;
|
||||
|
||||
@@ -346,10 +350,12 @@ v3d_csd_job_run(struct drm_sched_job *sc
|
||||
v3d_sched_stats_add_job(&v3d->gpu_queue_stats[V3D_CSD], sched_job);
|
||||
v3d_switch_perfmon(v3d, &job->base);
|
||||
|
||||
- for (i = 1; i <= 6; i++)
|
||||
- V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]);
|
||||
+ csd_cfg0_reg = v3d->ver < 71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0;
|
||||
+ csd_cfg_reg_count = v3d->ver < 71 ? 6 : 7;
|
||||
+ for (i = 1; i <= csd_cfg_reg_count; i++)
|
||||
+ V3D_CORE_WRITE(0, csd_cfg0_reg + 4 * i, job->args.cfg[i]);
|
||||
/* CFG0 write kicks off the job. */
|
||||
- V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0, job->args.cfg[0]);
|
||||
+ V3D_CORE_WRITE(0, csd_cfg0_reg, job->args.cfg[0]);
|
||||
|
||||
return fence;
|
||||
}
|
||||
@@ -452,7 +458,8 @@ v3d_csd_job_timedout(struct drm_sched_jo
|
||||
{
|
||||
struct v3d_csd_job *job = to_csd_job(sched_job);
|
||||
struct v3d_dev *v3d = job->base.v3d;
|
||||
- u32 batches = V3D_CORE_READ(0, V3D_CSD_CURRENT_CFG4);
|
||||
+ u32 batches = V3D_CORE_READ(0, (v3d->ver < 71 ? V3D_CSD_CURRENT_CFG4 :
|
||||
+ V3D_V7_CSD_CURRENT_CFG4));
|
||||
|
||||
/* If we've made progress, skip reset and let the timer get
|
||||
* rearmed.
|
@ -0,0 +1,24 @@
|
||||
From 22fb30936524ae96151789741885edbc45efb53d Mon Sep 17 00:00:00 2001
|
||||
From: Iago Toral Quiroga <itoral@igalia.com>
|
||||
Date: Thu, 2 Mar 2023 11:52:08 +0100
|
||||
Subject: [PATCH] drm/v3d: update UAPI to match user-space for V3D 7.x
|
||||
|
||||
V3D t.x takes a new parameter to configure TFU jobs that needs
|
||||
to be provided by user space.
|
||||
---
|
||||
include/uapi/drm/v3d_drm.h | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/include/uapi/drm/v3d_drm.h
|
||||
+++ b/include/uapi/drm/v3d_drm.h
|
||||
@@ -319,6 +319,10 @@ struct drm_v3d_submit_tfu {
|
||||
|
||||
/* Pointer to an array of ioctl extensions*/
|
||||
__u64 extensions;
|
||||
+
|
||||
+ struct {
|
||||
+ __u32 ioc;
|
||||
+ } v71;
|
||||
};
|
||||
|
||||
/* Submits a compute shader for dispatch. This job will block on any
|
@ -0,0 +1,19 @@
|
||||
From 18bc419d38eda06ded78c7b702c0e21e5af8f24c Mon Sep 17 00:00:00 2001
|
||||
From: Iago Toral Quiroga <itoral@igalia.com>
|
||||
Date: Thu, 2 Mar 2023 11:54:45 +0100
|
||||
Subject: [PATCH] drm/v3d: add brcm,2712-v3d as a compatible V3D device
|
||||
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_drv.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
|
||||
@@ -193,6 +193,7 @@ static const struct drm_driver v3d_drm_d
|
||||
};
|
||||
|
||||
static const struct of_device_id v3d_of_match[] = {
|
||||
+ { .compatible = "brcm,2712-v3d" },
|
||||
{ .compatible = "brcm,2711-v3d" },
|
||||
{ .compatible = "brcm,7268-v3d" },
|
||||
{ .compatible = "brcm,7278-v3d" },
|
@ -0,0 +1,64 @@
|
||||
From 12c7ea43b930976f35ce75d11fd3f55438868e13 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.com>
|
||||
Date: Fri, 4 Aug 2023 11:26:10 +0100
|
||||
Subject: [PATCH] drm/v3d: Improve MMU support for larger pages
|
||||
|
||||
The built-in MMU driver went most of the way towards supporting larger
|
||||
kernel pages, but dropped the ball when it comes to calculating indexes
|
||||
into the page table. Fix it.
|
||||
|
||||
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||||
---
|
||||
drivers/gpu/drm/v3d/v3d_mmu.c | 15 ++++++++-------
|
||||
1 file changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/v3d/v3d_mmu.c
|
||||
+++ b/drivers/gpu/drm/v3d/v3d_mmu.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "v3d_regs.h"
|
||||
|
||||
#define V3D_MMU_PAGE_SHIFT 12
|
||||
+#define V3D_PAGE_FACTOR (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT)
|
||||
|
||||
/* Note: All PTEs for the 1MB superpage must be filled with the
|
||||
* superpage bit set.
|
||||
@@ -88,7 +89,7 @@ void v3d_mmu_insert_ptes(struct v3d_bo *
|
||||
{
|
||||
struct drm_gem_shmem_object *shmem_obj = &bo->base;
|
||||
struct v3d_dev *v3d = to_v3d_dev(shmem_obj->base.dev);
|
||||
- u32 page = bo->node.start;
|
||||
+ u32 page = bo->node.start * V3D_PAGE_FACTOR;
|
||||
u32 page_prot = V3D_PTE_WRITEABLE | V3D_PTE_VALID;
|
||||
struct sg_dma_page_iter dma_iter;
|
||||
|
||||
@@ -98,13 +99,13 @@ void v3d_mmu_insert_ptes(struct v3d_bo *
|
||||
u32 pte = page_prot | page_address;
|
||||
u32 i;
|
||||
|
||||
- BUG_ON(page_address + (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT) >=
|
||||
+ BUG_ON(page_address + V3D_PAGE_FACTOR >=
|
||||
BIT(24));
|
||||
- for (i = 0; i < PAGE_SIZE >> V3D_MMU_PAGE_SHIFT; i++)
|
||||
+ for (i = 0; i < V3D_PAGE_FACTOR; i++)
|
||||
v3d->pt[page++] = pte + i;
|
||||
}
|
||||
|
||||
- WARN_ON_ONCE(page - bo->node.start !=
|
||||
+ WARN_ON_ONCE(page - (bo->node.start * V3D_PAGE_FACTOR) !=
|
||||
shmem_obj->base.size >> V3D_MMU_PAGE_SHIFT);
|
||||
|
||||
if (v3d_mmu_flush_all(v3d))
|
||||
@@ -115,10 +116,10 @@ void v3d_mmu_remove_ptes(struct v3d_bo *
|
||||
{
|
||||
struct v3d_dev *v3d = to_v3d_dev(bo->base.base.dev);
|
||||
u32 npages = bo->base.base.size >> V3D_MMU_PAGE_SHIFT;
|
||||
- u32 page;
|
||||
+ u32 page = bo->node.start * V3D_PAGE_FACTOR;
|
||||
|
||||
- for (page = bo->node.start; page < bo->node.start + npages; page++)
|
||||
- v3d->pt[page] = 0;
|
||||
+ while (npages--)
|
||||
+ v3d->pt[page++] = 0;
|
||||
|
||||
if (v3d_mmu_flush_all(v3d))
|
||||
dev_err(v3d->drm.dev, "MMU flush timeout\n");
|
@ -0,0 +1,19 @@
|
||||
From 5970fa51663511d7f773db7109ff6fa2504f186a Mon Sep 17 00:00:00 2001
|
||||
From: Iago Toral Quiroga <itoral@igalia.com>
|
||||
Date: Thu, 2 Mar 2023 11:56:52 +0100
|
||||
Subject: [PATCH] dt-bindings: gpu: v3d: Add BCM2712 to compatibility list
|
||||
|
||||
---
|
||||
Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
|
||||
+++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
|
||||
@@ -16,6 +16,7 @@ properties:
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
+ - brcm,2712-v3d
|
||||
- brcm,2711-v3d
|
||||
- brcm,7268-v3d
|
||||
- brcm,7278-v3d
|
@ -0,0 +1,328 @@
|
||||
From fdf9cab5eaa849e90b12e17718bc47130a91433c Mon Sep 17 00:00:00 2001
|
||||
From: Jonathan Bell <jonathan@raspberrypi.com>
|
||||
Date: Tue, 25 Apr 2023 15:52:13 +0100
|
||||
Subject: [PATCH] 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 | 276 +++++++++++++++++++++++++++++
|
||||
3 files changed, 285 insertions(+)
|
||||
create mode 100644 drivers/char/raspberrypi-gpiomem.c
|
||||
|
||||
--- a/drivers/char/Kconfig
|
||||
+++ b/drivers/char/Kconfig
|
||||
@@ -461,4 +461,12 @@ config RANDOM_TRUST_BOOTLOADER
|
||||
believe its RNG facilities may be faulty. This may also be configured
|
||||
at boot time with "random.trust_bootloader=on/off".
|
||||
|
||||
+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
|
||||
@@ -46,3 +46,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,276 @@
|
||||
+// 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(THIS_MODULE, 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 int 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);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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>");
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user