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:
Marty Jones 2024-01-18 16:23:52 -05:00 committed by Álvaro Fernández Rojas
parent 65f599223d
commit 2e715fb4fc
340 changed files with 69558 additions and 75 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ||

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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},

View File

@ -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>;

View File

@ -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";
};
};

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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,

View File

@ -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 */

View File

@ -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)

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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 = {

View File

@ -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?",

View File

@ -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",

View File

@ -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";

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -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 */

View File

@ -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,

View File

@ -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",

View File

@ -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";

View File

@ -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

View File

@ -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);
}

View File

@ -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>;
};
};

View File

@ -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);

View File

@ -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,
};

View File

@ -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;

View File

@ -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>/

View File

@ -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);
}

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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";
+ };
+};

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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),

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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");

View File

@ -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 = {

View File

@ -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,

View File

@ -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)

View File

@ -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"

View File

@ -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.

View File

@ -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

View File

@ -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" },

View File

@ -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");

View File

@ -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

View File

@ -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