bcm27xx: pull 6.6 patches from RPi repo
Some checks are pending
Build Kernel / Build all affected Kernels (push) Waiting to run
Build all core packages / Build all core packages for selected target (push) Waiting to run

Adds latest 6.6 patches from the Raspberry Pi repository.

These patches were generated from:
https://github.com/raspberrypi/linux/commits/rpi-6.6.y/
With the following command:
git format-patch -N v6.6.83..HEAD
(HEAD -> 08d4e8f52256bd422d8a1f876411603f627d0a82)

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
This commit is contained in:
Álvaro Fernández Rojas 2025-03-15 11:43:43 +01:00
parent 6403c2890c
commit 251f76c1c6
64 changed files with 9054 additions and 64 deletions

View File

@ -16,7 +16,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1387,6 +1387,9 @@ static int dwc3_core_init(struct dwc3 *d
@@ -1367,6 +1367,9 @@ static int dwc3_core_init(struct dwc3 *d
if (dwc->parkmode_disable_hs_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_HS;
@ -26,7 +26,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
if (DWC3_VER_IS_WITHIN(DWC3, 290A, ANY) &&
(dwc->maximum_speed == USB_SPEED_HIGH ||
dwc->maximum_speed == USB_SPEED_FULL))
@@ -1676,6 +1679,8 @@ static void dwc3_get_properties(struct d
@@ -1634,6 +1637,8 @@ static void dwc3_get_properties(struct d
"snps,parkmode-disable-ss-quirk");
dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev,
"snps,parkmode-disable-hs-quirk");
@ -37,7 +37,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -271,6 +271,7 @@
@@ -268,6 +268,7 @@
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
#define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16)
@ -45,7 +45,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
#define DWC3_GUCTL1_RESUME_OPMODE_HS_HOST BIT(10)
/* Global Status Register */
@@ -1122,10 +1123,12 @@ struct dwc3_scratchpad_array {
@@ -1118,10 +1119,12 @@ struct dwc3_scratchpad_array {
* generation after resume from suspend.
* @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin
* VBUS with an external supply.
@ -62,7 +62,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
* @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
* @tx_de_emphasis: Tx de-emphasis value
* 0 - -6dB de-emphasis
@@ -1352,6 +1355,7 @@ struct dwc3 {
@@ -1347,6 +1350,7 @@ struct dwc3 {
unsigned ulpi_ext_vbus_drv:1;
unsigned parkmode_disable_ss_quirk:1;
unsigned parkmode_disable_hs_quirk:1;

View File

@ -22,7 +22,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1381,6 +1381,12 @@ static int dwc3_core_init(struct dwc3 *d
@@ -1361,6 +1361,12 @@ static int dwc3_core_init(struct dwc3 *d
if (dwc->dis_tx_ipgap_linecheck_quirk)
reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
@ -35,7 +35,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
if (dwc->parkmode_disable_ss_quirk)
reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
@@ -1675,6 +1681,10 @@ static void dwc3_get_properties(struct d
@@ -1633,6 +1639,10 @@ static void dwc3_get_properties(struct d
"snps,resume-hs-terminations");
dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev,
"snps,ulpi-ext-vbus-drv");
@ -48,7 +48,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
dwc->parkmode_disable_hs_quirk = device_property_read_bool(dev,
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -269,6 +269,8 @@
@@ -266,6 +266,8 @@
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
#define DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK BIT(26)
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
@ -57,7 +57,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
#define DWC3_GUCTL1_PARKMODE_DISABLE_SS BIT(17)
#define DWC3_GUCTL1_PARKMODE_DISABLE_HS BIT(16)
#define DWC3_GUCTL1_PARKMODE_DISABLE_FSLS BIT(15)
@@ -1123,6 +1125,8 @@ struct dwc3_scratchpad_array {
@@ -1119,6 +1121,8 @@ struct dwc3_scratchpad_array {
* generation after resume from suspend.
* @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin
* VBUS with an external supply.
@ -66,7 +66,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
* @parkmode_disable_ss_quirk: If set, disable park mode feature for all
* Superspeed instances.
* @parkmode_disable_hs_quirk: If set, disable park mode feature for all
@@ -1353,6 +1357,8 @@ struct dwc3 {
@@ -1348,6 +1352,8 @@ struct dwc3 {
unsigned dis_tx_ipgap_linecheck_quirk:1;
unsigned resume_hs_terminations:1;
unsigned ulpi_ext_vbus_drv:1;

View File

@ -0,0 +1,246 @@
From 5fa4b1ff4db7635da04b1b8bf33b42a941064718 Mon Sep 17 00:00:00 2001
From: Kai-Uwe Herbing <155751635+herbingk@users.noreply.github.com>
Date: Tue, 31 Dec 2024 19:44:31 +0100
Subject: [PATCH] Add and update files for pwm-gpio-fan overlay
Add and update files for pwm-gpio-fan overlay
Signed-off-by: Kai-Uwe Herbing <155751635+herbingk@users.noreply.github.com>
---
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 40 +++++
.../dts/overlays/pwm-gpio-fan-overlay.dts | 170 ++++++++++++++++++
3 files changed, 211 insertions(+)
create mode 100644 arch/arm/boot/dts/overlays/pwm-gpio-fan-overlay.dts
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -219,6 +219,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
pwm.dtbo \
pwm-2chan.dtbo \
pwm-gpio.dtbo \
+ pwm-gpio-fan.dtbo \
pwm-ir-tx.dtbo \
pwm-pio.dtbo \
pwm1.dtbo \
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -4036,6 +4036,46 @@ Load: dtoverlay=pwm-gpio,<param>=<val>
Params: gpio Output pin (default 4)
+Name: pwm-gpio-fan
+Info: Configure a GPIO connected PWM cooling fan controlled by the
+ software-based GPIO PWM kernel module
+Load: dtoverlay=pwm-gpio-fan,<param>=<val>
+Params: fan_gpio BCM number of the pin driving the fan,
+ default 18 (GPIO 18)
+ fan_temp0 CPU temperature at which fan is started with
+ low speed in millicelsius,
+ default 55000 (55 °C)
+ fan_temp1 CPU temperature at which fan is switched
+ to medium speed in millicelsius,
+ default 60000 (60 °C)
+ fan_temp2 CPU temperature at which fan is switched
+ to high speed in millicelsius,
+ default 67500 (67.5 °C)
+ fan_temp3 CPU temperature at which fan is switched
+ to max speed in millicelsius,
+ default 75000 (75 °C)
+ fan_temp0_hyst Temperature hysteris at which fan is stopped
+ in millicelsius,default 5000 (resulting
+ in 50 °C)
+ fan_temp1_hyst Temperature hysteris at which fan is switched
+ back to low speed in millicelsius,
+ default 5000 (resulting in 55 °C)
+ fan_temp2_hyst Temperature hysteris at which fan is switched
+ back to medium speed in millicelsius,
+ default 5000 (resulting in 62.5 °C)
+ fan_temp3_hyst Temperature hysteris at which fan is switched
+ back to high speed in millicelsius,
+ default 5000 (resulting in 70 °C)
+ fan_temp0_speed Fan speed for low cooling state in range
+ 0 to 255, default 114 (45% PWM duty cycle)
+ fan_temp1_speed Fan speed for medium cooling state in range
+ 0 to 255, default 152 (60% PWM duty cycle)
+ fan_temp2_speed Fan speed for high cooling state in range
+ 0 to 255, default 204 (80% PWM duty cycle)
+ fan_temp3_speed Fan speed for max cooling state in range
+ 0 to 255, default 255 (100% PWM duty cycle)
+
+
Name: pwm-ir-tx
Info: Use GPIO pin as pwm-assisted infrared transmitter output.
This is an alternative to "gpio-ir-tx". pwm-ir-tx makes use
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/pwm-gpio-fan-overlay.dts
@@ -0,0 +1,170 @@
+/*
+ * Overlay for a GPIO connected PWM cooling fan controlled by software GPIO PWM
+ *
+ * Optional parameters:
+ * - "fan_gpio" BCM number of the pin driving the fan, default 18 (GPIO18)
+ *
+ * - "fan_temp0" CPU temperature at which fan is started with low speed in millicelsius,
+ * default 55000 (55 °C)
+ * - "fan_temp1" CPU temperature at which fan is switched to medium speed in millicelsius,
+ * default 60000 (60 °C)
+ * - "fan_temp2" CPU temperature at which fan is switched to high speed in millicelsius,
+ * default 67500 (67.5 °C)
+ * - "fan_temp3" CPU temperature at which fan is switched to max speed in millicelsius,
+ * default 75000 (75 °C)
+ * - "fan_temp0_hyst" Temperature hysteris at which fan is stopped in millicelsius,
+ * default 5000 (resulting in 50 °C)
+ * - "fan_temp1_hyst" Temperature hysteris at which fan is switched back to low speed
+ * in millicelsius, default 5000 (resulting in 55 °C)
+ * - "fan_temp2_hyst" Temperature hysteris at which fan is switched back to medium speed
+ * in millicelsius, default 5000 (resulting in 62.5 °C)
+ * - "fan_temp3_hyst" Temperature hysteris at which fan is switched back to high speed
+ * in millicelsius, default 5000 (resulting in 70 °C)
+ * - "fan_temp0_speed" Fan speed for low cooling state in range 0 to 255,
+ * default 114 (45% PWM duty cycle)
+ * - "fan_temp1_speed" Fan speed for medium cooling state in range 0 to 255,
+ * default 152 (60% PWM duty cycle)
+ * - "fan_temp2_speed" Fan speed for high cooling state in range 0 to 255,
+ * default 204 (80% PWM duty cycle)
+ * - "fan_temp3_speed" Fan speed for max cooling state in range 0 to 255,
+ * default 255 (100% PWM duty cycle)
+ *
+ * N.B.
+ * - Uses the software GPIO PWM kernel module instead of the Pis hardware PWMs (PWM0/PWM1).
+ * This will allow for an undisturbed concurrent usage of the Pis analogue audio output.
+ *
+ * Requires:
+ * - A PWM controlled cooling fan connected to the GPIO, such as an
+ * Argon mini-fan, HighPi Pro Fan or Waveshare FAN-4020-PWM-5V
+ * - Raspberry Pi OS Bookworm with kernel 6.6.62 or above
+ *
+ * Build:
+ * - sudo dtc -I dts -O dtb -o /boot/firmware/overlays/pwm-gpiofan.dtbo pwm-gpiofan-overlay.dts
+ *
+ * Activate:
+ * - sudo nano /boot/firmware/config.txt add "dtoverlay=pwm-gpiofan"
+ *
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+ pwm_gpio_pins: pwm_gpio_pins {
+ brcm,pins = <18>; /* gpio-pin = 18 */
+ brcm,function = <1>; /* gpio function = output */
+ brcm,pull = <0>; /* gpio pull up/down = off */
+ };
+ };
+ };
+
+ fragment@1 {
+ target-path = "/";
+ __overlay__ {
+ pwm_gpio: pwm_gpio {
+ compatible="pwm-gpio";
+ #pwm-cells = <2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm_gpio_pins>;
+ gpios = <&gpio 18 0>; /* gpio-pin = 18 */
+ };
+ };
+ };
+
+ fragment@2 {
+ target-path = "/";
+ __overlay__ {
+ fan0: pwm-fan {
+ compatible = "pwm-fan";
+ #cooling-cells = <2>;
+ /* in ns = 20ms = 50 Hz */
+ pwms = <&pwm_gpio 0 20000000 0>;
+
+ cooling-min-state = <0>;
+ cooling-max-state = <4>;
+ /* PWM duty cycle values in a range from 0 to 255 */
+ /* which correspond to thermal cooling states 0 to 4 */
+ cooling-levels = <0 114 152 204 255>;
+ };
+ };
+ };
+
+ fragment@3 {
+ target = <&cpu_thermal>;
+ __overlay__ {
+ /* in ms = poll every 2s */
+ polling-delay = <2000>;
+ };
+ };
+
+ fragment@4 {
+ target = <&thermal_trips>;
+ __overlay__ {
+ /* below temperatures in millicelsius */
+ trip0: trip0 {
+ temperature = <55000>; /* 55 °C */
+ hysteresis = <5000>; /* 5 °C */
+ type = "active";
+ };
+ trip1: trip1 {
+ temperature = <60000>; /* 60 °C */
+ hysteresis = <5000>; /* 5 °C */
+ type = "active";
+ };
+ trip2: trip2 {
+ temperature = <67500>; /* 67.5 °C */
+ hysteresis = <5000>; /* 5 °C */
+ type = "active";
+ };
+ trip3: trip3 {
+ temperature = <75000>; /* 75 °C */
+ hysteresis = <5000>; /* 5 °C */
+ type = "active";
+ };
+ };
+ };
+
+ fragment@5 {
+ target = <&cooling_maps>;
+ __overlay__ {
+ map0 {
+ cooling-device = <&fan0 0 1>;
+ trip = <&trip0>;
+ };
+ map1 {
+ cooling-device = <&fan0 1 2>;
+ trip = <&trip1>;
+ };
+ map2 {
+ cooling-device = <&fan0 2 3>;
+ trip = <&trip2>;
+ };
+ map3 {
+ cooling-device = <&fan0 3 4>;
+ trip = <&trip3>;
+ };
+ };
+ };
+
+ __overrides__ {
+ fan_gpio = <&pwm_gpio>,"gpios:4",
+ <&pwm_gpio_pins>,"brcm,pins:0";
+ fan_temp0 = <&trip0>,"temperature:0";
+ fan_temp0_hyst = <&trip0>,"hysteresis:0";
+ fan_temp0_speed = <&fan0>,"cooling-levels:4";
+ fan_temp1 = <&trip1>,"temperature:0";
+ fan_temp1_hyst = <&trip1>,"hysteresis:0";
+ fan_temp1_speed = <&fan0>,"cooling-levels:8";
+ fan_temp2 = <&trip2>,"temperature:0";
+ fan_temp2_hyst = <&trip2>,"hysteresis:0";
+ fan_temp2_speed = <&fan0>,"cooling-levels:12";
+ fan_temp3 = <&trip3>,"temperature:0";
+ fan_temp3_hyst = <&trip3>,"hysteresis:0";
+ fan_temp3_speed = <&fan0>,"cooling-levels:16";
+ };
+
+};

View File

@ -0,0 +1,71 @@
From b3dd7e8947cddec41864e8d3ce5f5d8b81033d6a Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 20 Nov 2024 19:17:03 +0000
Subject: [PATCH] media: i2c: imx290: Limit analogue gain according to module
Commit ec75fd952b0b5cdab7b606cdacba237c57c1fdda upstream.
The imx327 only supports up to 29.4dB of analogue gain, vs
the imx290 going up to 30dB. Both are in 0.3dB steps.
As we now have model specific config, fix this mismatch,
and delete the comment referencing it.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/i2c/imx290.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -178,6 +178,7 @@ struct imx290_model_info {
enum imx290_colour_variant colour_variant;
const struct cci_reg_sequence *init_regs;
size_t init_regs_num;
+ unsigned int max_analog_gain;
const char *name;
};
@@ -879,14 +880,10 @@ static int imx290_ctrl_init(struct imx29
* up to 72.0dB (240) add further digital gain. Limit the range to
* analog gain only, support for digital gain can be added separately
* if needed.
- *
- * The IMX327 and IMX462 are largely compatible with the IMX290, but
- * have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
- * gain. When support for those sensors gets added to the driver, the
- * gain control should be adjusted accordingly.
*/
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
- V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
+ V4L2_CID_ANALOGUE_GAIN, 0,
+ imx290->model->max_analog_gain, 1, 0);
/*
* Correct range will be determined through imx290_ctrl_update setting
@@ -1437,18 +1434,21 @@ static const struct imx290_model_info im
.colour_variant = IMX290_VARIANT_COLOUR,
.init_regs = imx290_global_init_settings_290,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290),
+ .max_analog_gain = 100,
.name = "imx290",
},
[IMX290_MODEL_IMX290LLR] = {
.colour_variant = IMX290_VARIANT_MONO,
.init_regs = imx290_global_init_settings_290,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_290),
+ .max_analog_gain = 100,
.name = "imx290",
},
[IMX290_MODEL_IMX327LQR] = {
.colour_variant = IMX290_VARIANT_COLOUR,
.init_regs = imx290_global_init_settings_327,
.init_regs_num = ARRAY_SIZE(imx290_global_init_settings_327),
+ .max_analog_gain = 98,
.name = "imx327",
},
};

View File

@ -0,0 +1,31 @@
From f4f17c3fe223b3d8ad65f5420abbcd69ef901186 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 20 Nov 2024 19:17:05 +0000
Subject: [PATCH] media: dt-bindings: sony,imx290: Add IMX462 to the IMX290
binding
Commit e4faac99d5bb4b6c80f2495c40fcd71a67c40b27 upstream.
IMX462 is the successor to IMX290, which is supportable by
the existing IMX290 driver via a new compatible string.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml | 2 ++
1 file changed, 2 insertions(+)
--- a/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx290.yaml
@@ -30,6 +30,8 @@ properties:
- sony,imx290lqr # Colour
- sony,imx290llr # Monochrome
- sony,imx327lqr # Colour
+ - sony,imx462lqr # Colour
+ - sony,imx462llr # Monochrome
- const: sony,imx290
deprecated: true

View File

@ -0,0 +1,116 @@
From 23037697914a6d1220768a752c6358d35ca03737 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 20 Nov 2024 19:17:06 +0000
Subject: [PATCH] media: i2c: imx290: Add configuration for IMX462
Commit c699b6c7c857baba1375a1ed090bf71f695e2971 upstream.
IMX462 is the successor to IMX290, and wants very minor
changes to the register setup.
Add the relevant configuration to support it.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
drivers/media/i2c/imx290.c | 66 ++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -172,6 +172,8 @@ enum imx290_model {
IMX290_MODEL_IMX290LQR,
IMX290_MODEL_IMX290LLR,
IMX290_MODEL_IMX327LQR,
+ IMX290_MODEL_IMX462LQR,
+ IMX290_MODEL_IMX462LLR,
};
struct imx290_model_info {
@@ -318,6 +320,50 @@ static const struct cci_reg_sequence imx
{ CCI_REG8(0x33b3), 0x04 },
};
+static const struct cci_reg_sequence imx290_global_init_settings_462[] = {
+ { CCI_REG8(0x300f), 0x00 },
+ { CCI_REG8(0x3010), 0x21 },
+ { CCI_REG8(0x3011), 0x02 },
+ { CCI_REG8(0x3016), 0x09 },
+ { CCI_REG8(0x3070), 0x02 },
+ { CCI_REG8(0x3071), 0x11 },
+ { CCI_REG8(0x309b), 0x10 },
+ { CCI_REG8(0x309c), 0x22 },
+ { CCI_REG8(0x30a2), 0x02 },
+ { CCI_REG8(0x30a6), 0x20 },
+ { CCI_REG8(0x30a8), 0x20 },
+ { CCI_REG8(0x30aa), 0x20 },
+ { CCI_REG8(0x30ac), 0x20 },
+ { CCI_REG8(0x30b0), 0x43 },
+ { CCI_REG8(0x3119), 0x9e },
+ { CCI_REG8(0x311c), 0x1e },
+ { CCI_REG8(0x311e), 0x08 },
+ { CCI_REG8(0x3128), 0x05 },
+ { CCI_REG8(0x313d), 0x83 },
+ { CCI_REG8(0x3150), 0x03 },
+ { CCI_REG8(0x317e), 0x00 },
+ { CCI_REG8(0x32b8), 0x50 },
+ { CCI_REG8(0x32b9), 0x10 },
+ { CCI_REG8(0x32ba), 0x00 },
+ { CCI_REG8(0x32bb), 0x04 },
+ { CCI_REG8(0x32c8), 0x50 },
+ { CCI_REG8(0x32c9), 0x10 },
+ { CCI_REG8(0x32ca), 0x00 },
+ { CCI_REG8(0x32cb), 0x04 },
+ { CCI_REG8(0x332c), 0xd3 },
+ { CCI_REG8(0x332d), 0x10 },
+ { CCI_REG8(0x332e), 0x0d },
+ { CCI_REG8(0x3358), 0x06 },
+ { CCI_REG8(0x3359), 0xe1 },
+ { CCI_REG8(0x335a), 0x11 },
+ { CCI_REG8(0x3360), 0x1e },
+ { CCI_REG8(0x3361), 0x61 },
+ { CCI_REG8(0x3362), 0x10 },
+ { CCI_REG8(0x33b0), 0x50 },
+ { CCI_REG8(0x33b2), 0x1a },
+ { CCI_REG8(0x33b3), 0x04 },
+};
+
#define IMX290_NUM_CLK_REGS 2
static const struct cci_reg_sequence xclk_regs[][IMX290_NUM_CLK_REGS] = {
[IMX290_CLK_37_125] = {
@@ -1451,6 +1497,20 @@ static const struct imx290_model_info im
.max_analog_gain = 98,
.name = "imx327",
},
+ [IMX290_MODEL_IMX462LQR] = {
+ .colour_variant = IMX290_VARIANT_COLOUR,
+ .init_regs = imx290_global_init_settings_462,
+ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_462),
+ .max_analog_gain = 98,
+ .name = "imx462",
+ },
+ [IMX290_MODEL_IMX462LLR] = {
+ .colour_variant = IMX290_VARIANT_MONO,
+ .init_regs = imx290_global_init_settings_462,
+ .init_regs_num = ARRAY_SIZE(imx290_global_init_settings_462),
+ .max_analog_gain = 98,
+ .name = "imx462",
+ },
};
static int imx290_parse_dt(struct imx290 *imx290)
@@ -1646,6 +1706,12 @@ static const struct of_device_id imx290_
}, {
.compatible = "sony,imx327lqr",
.data = &imx290_models[IMX290_MODEL_IMX327LQR],
+ }, {
+ .compatible = "sony,imx462lqr",
+ .data = &imx290_models[IMX290_MODEL_IMX462LQR],
+ }, {
+ .compatible = "sony,imx462llr",
+ .data = &imx290_models[IMX290_MODEL_IMX462LLR],
},
{ /* sentinel */ },
};

View File

@ -0,0 +1,60 @@
From c633c2e93e460925120e0817c14bbfc444a70226 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 15 May 2024 12:43:15 +0100
Subject: [PATCH] media: imx290: Add module parameter to allow selection of HCG
mode
The sensor has Low Conversion Gain (HCG) and High Conversion Gain (HCG)
modes, with the supposedly the HCG mode having better noise performance
at high gains.
As this parameter changes the gain range of the sensor, it isn't
possible to make this an automatic property, and there is no
suitable V4L2 control to set it, so just add it as a module parameter.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx290.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -13,6 +13,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -41,6 +42,9 @@
#define IMX290_WINMODE_720P (1 << 4)
#define IMX290_WINMODE_CROP (4 << 4)
#define IMX290_FR_FDG_SEL CCI_REG8(0x3009)
+#define IMX290_FDG_HCG BIT(4)
+#define IMX290_FRSEL_60FPS BIT(0)
+#define IMX290_FDG_LCG 0
#define IMX290_BLKLEVEL CCI_REG16_LE(0x300a)
#define IMX290_GAIN CCI_REG8(0x3014)
#define IMX290_VMAX CCI_REG24_LE(0x3018)
@@ -162,6 +166,10 @@
#define IMX290_NUM_SUPPLIES 3
+static bool hcg_mode;
+module_param(hcg_mode, bool, 0664);
+MODULE_PARM_DESC(hcg_mode, "Enable HCG mode");
+
enum imx290_colour_variant {
IMX290_VARIANT_COLOUR,
IMX290_VARIANT_MONO,
@@ -697,7 +705,8 @@ static int imx290_set_data_lanes(struct
&ret);
cci_write(imx290->regmap, IMX290_CSI_LANE_MODE, imx290->nlanes - 1,
&ret);
- cci_write(imx290->regmap, IMX290_FR_FDG_SEL, 0x01, &ret);
+ cci_write(imx290->regmap, IMX290_FR_FDG_SEL, IMX290_FRSEL_60FPS |
+ (hcg_mode ? IMX290_FDG_HCG : IMX290_FDG_LCG), &ret);
return ret;
}

View File

@ -0,0 +1,47 @@
From eec7048c4e3aec1aadc21fcffcf6be9f5385f72a Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 12 Nov 2024 14:15:30 +0000
Subject: [PATCH] dtoverlays: Switch imx462 overlay to use the new compatible
Now that imx462 has a separate compatible string, make use of it.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
arch/arm/boot/dts/overlays/imx462-overlay.dts | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
--- a/arch/arm/boot/dts/overlays/imx462-overlay.dts
+++ b/arch/arm/boot/dts/overlays/imx462-overlay.dts
@@ -1,9 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Definitions for IMX462 camera module on VC I2C bus
-// IMX462 is the successor to IMX290. The drivers currently don't support
-// any additional feature of IMX462, so use the IMX290 compatible strings
-// for now.
+// IMX462 is the successor to IMX290.
/dts-v1/;
/plugin/;
@@ -17,19 +15,17 @@
// Fragment numbers deliberately high to avoid conflicts with the
// included imx290_327 overlay file.
- //IMX462 is not defined in the bindings, so use IMX290 for now.
-
fragment@101 {
target = <&cam_node>;
__overlay__ {
- compatible = "sony,imx290lqr";
+ compatible = "sony,imx462lqr";
};
};
fragment@102 {
target = <&cam_node>;
__dormant__ {
- compatible = "sony,imx290llr";
+ compatible = "sony,imx462llr";
};
};

View File

@ -0,0 +1,327 @@
From 0a0814f830829b1a377273ddb09c156c84e1a8ca Mon Sep 17 00:00:00 2001
From: Alexander Stein <alexander.stein@ew.tq-group.com>
Date: Wed, 17 Jan 2024 08:39:36 +0100
Subject: [PATCH] media: i2c: imx415: Add more clock configurations
Commit b814b5b2ec2d327b79e415c1baa5eecdf9aa786b upstream.
Complete the list from "INCK Setting" section in IMX415-AAQR-C
(Rev. E19504, 2019/05/21). For consistency suffix all lane rate values by
UL, which is needed for 2376000000 anyway.
Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
---
drivers/media/i2c/imx415.c | 265 ++++++++++++++++++++++++++++++++++++-
1 file changed, 260 insertions(+), 5 deletions(-)
--- a/drivers/media/i2c/imx415.c
+++ b/drivers/media/i2c/imx415.c
@@ -124,7 +124,7 @@ struct imx415_clk_params {
/* INCK Settings - includes all lane rate and INCK dependent registers */
static const struct imx415_clk_params imx415_clk_params[] = {
{
- .lane_rate = 594000000,
+ .lane_rate = 594000000UL,
.inck = 27000000,
.regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
.regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
@@ -139,7 +139,37 @@ static const struct imx415_clk_params im
.regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
},
{
- .lane_rate = 720000000,
+ .lane_rate = 594000000UL,
+ .inck = 37125000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B },
+ .regs[2] = { IMX415_SYS_MODE, 0x7 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x24 },
+ .regs[5] = { IMX415_INCKSEL3, 0x080 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x24 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0984 },
+ },
+ {
+ .lane_rate = 594000000UL,
+ .inck = 74250000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 },
+ .regs[2] = { IMX415_SYS_MODE, 0x7 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x080 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 },
+ },
+ {
+ .lane_rate = 720000000UL,
.inck = 24000000,
.regs[0] = { IMX415_BCWAIT_TIME, 0x054 },
.regs[1] = { IMX415_CPWAIT_TIME, 0x03B },
@@ -154,7 +184,22 @@ static const struct imx415_clk_params im
.regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 },
},
{
- .lane_rate = 891000000,
+ .lane_rate = 720000000UL,
+ .inck = 72000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 },
+ .regs[2] = { IMX415_SYS_MODE, 0x9 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0A0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 },
+ },
+ {
+ .lane_rate = 891000000UL,
.inck = 27000000,
.regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
.regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
@@ -169,7 +214,37 @@ static const struct imx415_clk_params im
.regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
},
{
- .lane_rate = 1440000000,
+ .lane_rate = 891000000UL,
+ .inck = 37125000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B },
+ .regs[2] = { IMX415_SYS_MODE, 0x5 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x24 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x24 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 },
+ },
+ {
+ .lane_rate = 891000000UL,
+ .inck = 74250000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 },
+ .regs[2] = { IMX415_SYS_MODE, 0x5 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x0 },
+ .regs[9] = { IMX415_INCKSEL7, 0x1 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 },
+ },
+ {
+ .lane_rate = 1440000000UL,
.inck = 24000000,
.regs[0] = { IMX415_BCWAIT_TIME, 0x054 },
.regs[1] = { IMX415_CPWAIT_TIME, 0x03B },
@@ -184,7 +259,22 @@ static const struct imx415_clk_params im
.regs[10] = { IMX415_TXCLKESC_FREQ, 0x0600 },
},
{
- .lane_rate = 1485000000,
+ .lane_rate = 1440000000UL,
+ .inck = 72000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0F8 },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B0 },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0A0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1200 },
+ },
+ {
+ .lane_rate = 1485000000UL,
.inck = 27000000,
.regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
.regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
@@ -198,6 +288,171 @@ static const struct imx415_clk_params im
.regs[9] = { IMX415_INCKSEL7, 0x0 },
.regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
},
+ {
+ .lane_rate = 1485000000UL,
+ .inck = 37125000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x24 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0A0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x24 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 },
+ },
+ {
+ .lane_rate = 1485000000UL,
+ .inck = 74250000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 },
+ .regs[2] = { IMX415_SYS_MODE, 0x8 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0A0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 },
+ },
+ {
+ .lane_rate = 1782000000UL,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x4 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C6 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 1782000000UL,
+ .inck = 37125000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B },
+ .regs[2] = { IMX415_SYS_MODE, 0x4 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x24 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x24 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 },
+ },
+ {
+ .lane_rate = 1782000000UL,
+ .inck = 74250000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 },
+ .regs[2] = { IMX415_SYS_MODE, 0x4 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0C0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 },
+ },
+ {
+ .lane_rate = 2079000000UL,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x2 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0E7 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 2079000000UL,
+ .inck = 37125000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B },
+ .regs[2] = { IMX415_SYS_MODE, 0x2 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x24 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0E0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x24 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 },
+ },
+ {
+ .lane_rate = 2079000000UL,
+ .inck = 74250000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 },
+ .regs[2] = { IMX415_SYS_MODE, 0x2 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x0E0 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 },
+ },
+ {
+ .lane_rate = 2376000000UL,
+ .inck = 27000000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x05D },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x042 },
+ .regs[2] = { IMX415_SYS_MODE, 0x0 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x23 },
+ .regs[5] = { IMX415_INCKSEL3, 0x108 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E7 },
+ .regs[7] = { IMX415_INCKSEL5, 0x23 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x06C0 },
+ },
+ {
+ .lane_rate = 2376000000UL,
+ .inck = 37125000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x07F },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x05B },
+ .regs[2] = { IMX415_SYS_MODE, 0x0 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x24 },
+ .regs[5] = { IMX415_INCKSEL3, 0x100 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x24 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x0948 },
+ },
+ {
+ .lane_rate = 2376000000UL,
+ .inck = 74250000,
+ .regs[0] = { IMX415_BCWAIT_TIME, 0x0FF },
+ .regs[1] = { IMX415_CPWAIT_TIME, 0x0B6 },
+ .regs[2] = { IMX415_SYS_MODE, 0x0 },
+ .regs[3] = { IMX415_INCKSEL1, 0x00 },
+ .regs[4] = { IMX415_INCKSEL2, 0x28 },
+ .regs[5] = { IMX415_INCKSEL3, 0x100 },
+ .regs[6] = { IMX415_INCKSEL4, 0x0E0 },
+ .regs[7] = { IMX415_INCKSEL5, 0x28 },
+ .regs[8] = { IMX415_INCKSEL6, 0x1 },
+ .regs[9] = { IMX415_INCKSEL7, 0x0 },
+ .regs[10] = { IMX415_TXCLKESC_FREQ, 0x1290 },
+ },
};
/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */

View File

@ -0,0 +1,214 @@
From 384e58f63a3a328f7f656052b6357f3408aac6c3 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 31 Dec 2024 20:33:46 +0000
Subject: [PATCH] dtoverlays: Add overlay for Sony IMX415 image sensor
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 31 +++++
arch/arm/boot/dts/overlays/imx415-overlay.dts | 116 ++++++++++++++++++
arch/arm/boot/dts/overlays/imx415.dtsi | 27 ++++
4 files changed, 175 insertions(+)
create mode 100644 arch/arm/boot/dts/overlays/imx415-overlay.dts
create mode 100644 arch/arm/boot/dts/overlays/imx415.dtsi
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -135,6 +135,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
imx296.dtbo \
imx327.dtbo \
imx378.dtbo \
+ imx415.dtbo \
imx462.dtbo \
imx477.dtbo \
imx500.dtbo \
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -2859,6 +2859,37 @@ Params: rotation Mounting
450000000 (default), 453000000, 456000000.
+Name: imx415
+Info: Sony IMX415 camera module.
+ Uses Unicam 1, which is the standard camera connector on most Pi
+ variants. By default this uses 4 CSI2 data lanes, so requires a
+ Compute Module or Pi5.
+Load: dtoverlay=imx415,<param>
+Params: addr Set I2C address of sensor. Valid values are
+ 0x10, 0x1a, 0x36 and 0x37. Default is 0x37.
+ 4lane Enable 4 CSI2 data lanes.
+ clock-frequency Sets the clock frequency to match that used on
+ the board.
+ Valid values are 24, 27, 37.125, 72, or
+ 74.25MHz.
+ The default is 24MHz.
+ Note that the link frequencies permitted vary
+ based on the oscillator used.
+ link-frequency Confgures the link frequency to be used. Note
+ that the permitted values vary based on
+ clock-frequency and number of lanes.
+ The default is 360MHz for 720Mbit/s.
+ orientation Sensor orientation (0 = front, 1 = rear,
+ 2 = external, default external)
+ rotation Mounting rotation of the camera sensor (0 or
+ 180, default 0)
+ media-controller Configure use of Media Controller API for
+ configuring the sensor (default on)
+ cam0 Adopt the default configuration for CAM0 on a
+ Compute Module (CSI0, i2c_vc, and cam0_reg).
+ vcm Enable ad5398 VCM associated with the sensor.
+
+
Name: imx462
Info: Sony IMX462 camera module.
Uses Unicam 1, which is the standard camera connector on most Pi
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/imx415-overlay.dts
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Definitions for IMX415 camera module on VC I2C bus
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/{
+ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2c0if>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+ clk_frag: fragment@1 {
+ target = <&cam1_clk>;
+ cam_clk: __overlay__ {
+ status = "okay";
+ clock-frequency = <24000000>;
+ };
+ };
+
+ fragment@2 {
+ target = <&i2c0mux>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+
+ reg_frag: fragment@3 {
+ target = <&cam1_reg>;
+ cam_reg: __overlay__ {
+ startup-delay-us = <100000>;
+ };
+ };
+
+ i2c_frag: fragment@100 {
+ target = <&i2c_csi_dsi>;
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ #include "imx415.dtsi"
+
+ vcm: ad5398@c {
+ compatible = "adi,ad5398";
+ reg = <0x0c>;
+ status = "disabled";
+ VANA-supply = <&cam1_reg>;
+ };
+ };
+ };
+
+ csi_frag: fragment@101 {
+ target = <&csi1>;
+ csi: __overlay__ {
+ status = "okay";
+ brcm,media-controller;
+
+ port {
+ csi_ep: endpoint {
+ remote-endpoint = <&cam_endpoint>;
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ clock-noncontinuous;
+ };
+ };
+ };
+ };
+
+ fragment@201 {
+ target = <&cam_endpoint>;
+ __dormant__ {
+ data-lanes = <1 2 3 4>;
+ };
+ };
+
+ fragment@202 {
+ target = <&csi_ep>;
+ __dormant__ {
+ data-lanes = <1 2 3 4>;
+ };
+ };
+
+
+ __overrides__ {
+ addr = <&cam_node>, "reg:0";
+ rotation = <&cam_node>,"rotation:0";
+ orientation = <&cam_node>,"orientation:0";
+ media-controller = <&csi>,"brcm,media-controller?";
+ cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
+ <&csi_frag>, "target:0=",<&csi0>,
+ <&reg_frag>, "target:0=",<&cam0_reg>,
+ <&clk_frag>, "target:0=",<&cam0_clk>,
+ <&cam_node>, "clocks:0=",<&cam0_clk>,
+ <&cam_node>, "avdd-supply:0=",<&cam0_reg>,
+ <&vcm>, "VANA-supply:0=", <&cam0_reg>;
+ vcm = <&vcm>, "status=okay",
+ <&cam_node>,"lens-focus:0=", <&vcm>;
+ clock-frequency = <&cam_clk>, "clock-frequency:0";
+ link-frequency = <&cam_endpoint>,"link-frequencies#0";
+ 4lane = <0>, "+201+202";
+ };
+};
+
+&cam_node {
+ status = "okay";
+};
+
+&cam_endpoint {
+ remote-endpoint = <&csi_ep>;
+};
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/imx415.dtsi
@@ -0,0 +1,27 @@
+// Fragment that configures an imx415
+
+cam_node: imx415@37 {
+ compatible = "sony,imx415";
+ reg = <0x37>;
+ status = "disabled";
+
+ clocks = <&cam1_clk>;
+ clock-names = "inck";
+
+ avdd-supply = <&cam1_reg>; /* 2.8v */
+ dvdd-supply = <&cam_dummy_reg>; /* 1.8v */
+ ovdd-supply = <&cam_dummy_reg>; /* 1.2v */
+
+ rotation = <180>;
+ orientation = <2>;
+
+ port {
+ cam_endpoint: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ //clock-noncontinuous;
+ link-frequencies =
+ /bits/ 64 <360000000>;
+ };
+ };
+};

View File

@ -0,0 +1,146 @@
From 4e8d73ce89c6dd6fdcb8dd7df8310762707c5b1a Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 1 Jan 2025 14:18:25 +0000
Subject: [PATCH] media: i2c: imx415: Add read/write control of VBLANK
This also requires that the ranges for the exposure control
are updated.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx415.c | 52 +++++++++++++++++++++++++-------------
1 file changed, 34 insertions(+), 18 deletions(-)
--- a/drivers/media/i2c/imx415.c
+++ b/drivers/media/i2c/imx415.c
@@ -25,6 +25,7 @@
#define IMX415_PIXEL_ARRAY_WIDTH 3864
#define IMX415_PIXEL_ARRAY_HEIGHT 2192
#define IMX415_PIXEL_ARRAY_VBLANK 58
+#define IMX415_EXPOSURE_OFFSET 8
#define IMX415_NUM_CLK_PARAM_REGS 11
@@ -56,6 +57,7 @@
#define IMX415_OUTSEL IMX415_REG_8BIT(0x30C0)
#define IMX415_DRV IMX415_REG_8BIT(0x30C1)
#define IMX415_VMAX IMX415_REG_24BIT(0x3024)
+#define IMX415_VMAX_MAX 0xfffff
#define IMX415_HMAX IMX415_REG_16BIT(0x3028)
#define IMX415_SHR0 IMX415_REG_24BIT(0x3050)
#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090)
@@ -457,7 +459,6 @@ static const struct imx415_clk_params im
/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */
static const struct imx415_reg imx415_mode_2_720[] = {
- { IMX415_VMAX, 0x08CA },
{ IMX415_HMAX, 0x07F0 },
{ IMX415_LANEMODE, IMX415_LANEMODE_2 },
{ IMX415_TCLKPOST, 0x006F },
@@ -473,7 +474,6 @@ static const struct imx415_reg imx415_mo
/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */
static const struct imx415_reg imx415_mode_2_1440[] = {
- { IMX415_VMAX, 0x08CA },
{ IMX415_HMAX, 0x042A },
{ IMX415_LANEMODE, IMX415_LANEMODE_2 },
{ IMX415_TCLKPOST, 0x009F },
@@ -489,7 +489,6 @@ static const struct imx415_reg imx415_mo
/* all-pixel 4-lane 891 Mbps 30 Hz mode */
static const struct imx415_reg imx415_mode_4_891[] = {
- { IMX415_VMAX, 0x08CA },
{ IMX415_HMAX, 0x044C },
{ IMX415_LANEMODE, IMX415_LANEMODE_4 },
{ IMX415_TCLKPOST, 0x007F },
@@ -617,6 +616,7 @@ struct imx415 {
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *exposure;
unsigned int cur_mode;
unsigned int num_data_lanes;
@@ -795,16 +795,37 @@ static int imx415_s_ctrl(struct v4l2_ctr
ctrls);
const struct v4l2_mbus_framefmt *format;
struct v4l2_subdev_state *state;
+ u32 exposure_max;
unsigned int vmax;
unsigned int flip;
-
- if (!sensor->streaming)
- return 0;
+ int ret;
state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ exposure_max = format->height + ctrl->val -
+ IMX415_EXPOSURE_OFFSET;
+ __v4l2_ctrl_modify_range(sensor->exposure,
+ sensor->exposure->minimum,
+ exposure_max, sensor->exposure->step,
+ sensor->exposure->default_value);
+ }
+
+ if (!sensor->streaming)
+ return 0;
+
switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ ret = imx415_write(sensor, IMX415_VMAX,
+ format->height + ctrl->val);
+ if (ret)
+ return ret;
+ /*
+ * Deliberately fall through as exposure is set based on VMAX
+ * which has just changed.
+ */
+ fallthrough;
case V4L2_CID_EXPOSURE:
/* clamp the exposure value to VMAX. */
vmax = format->height + sensor->vblank->cur.val;
@@ -840,7 +861,8 @@ static int imx415_ctrls_init(struct imx4
u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate;
u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate;
u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT +
- IMX415_PIXEL_ARRAY_VBLANK - 8;
+ IMX415_PIXEL_ARRAY_VBLANK -
+ IMX415_EXPOSURE_OFFSET;
u32 hblank;
unsigned int i;
int ret;
@@ -869,8 +891,9 @@ static int imx415_ctrls_init(struct imx4
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops, V4L2_CID_EXPOSURE,
- 4, exposure_max, 1, exposure_max);
+ sensor->exposure = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
+ V4L2_CID_EXPOSURE, 4,
+ exposure_max, 1, exposure_max);
v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
V4L2_CID_ANALOGUE_GAIN, IMX415_AGAIN_MIN,
@@ -887,16 +910,9 @@ static int imx415_ctrls_init(struct imx4
sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
V4L2_CID_VBLANK,
IMX415_PIXEL_ARRAY_VBLANK,
- IMX415_PIXEL_ARRAY_VBLANK, 1,
- IMX415_PIXEL_ARRAY_VBLANK);
- if (sensor->vblank)
- sensor->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- /*
- * The pixel rate used here is a virtual value and can be used for
- * calculating the frame rate together with hblank. It may not
- * necessarily be the physically correct pixel clock.
- */
+ IMX415_VMAX_MAX - IMX415_PIXEL_ARRAY_HEIGHT,
+ 1, IMX415_PIXEL_ARRAY_VBLANK);
+
v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate,
pixel_rate, 1, pixel_rate);

View File

@ -0,0 +1,231 @@
From 6722e1358768671c1e5761aa092efb4ae62b2c46 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Wed, 1 Jan 2025 17:01:34 +0000
Subject: [PATCH] media: i2c: imx415: Make HBLANK controllable and in
consistent units
The control of HMAX documented in the datasheet is consistent
with being in terms of a scaled INCK, being always 72MHz or
74.25MHz. It is NOT link frequency dependent, but the minimum
value for HMAX is dictated by the link frequency.
If PIXEL_RATE is defined as being 12 times the 72 or 74.25MHz,
and all values are scaled down again when writing HMAX, then
the numbers all work out regardless of INCK or link frequency.
Retain an hmax_min (set to the same value as the previous fixed
hmax register value) to set as the default value to avoid changing
the behaviour for existing users.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx415.c | 86 +++++++++++++++++---------------------
1 file changed, 38 insertions(+), 48 deletions(-)
--- a/drivers/media/i2c/imx415.c
+++ b/drivers/media/i2c/imx415.c
@@ -27,6 +27,9 @@
#define IMX415_PIXEL_ARRAY_VBLANK 58
#define IMX415_EXPOSURE_OFFSET 8
+#define IMX415_PIXEL_RATE_74_25MHZ 891000000
+#define IMX415_PIXEL_RATE_72MHZ 864000000
+
#define IMX415_NUM_CLK_PARAM_REGS 11
#define IMX415_REG_8BIT(n) ((1 << 16) | (n))
@@ -59,6 +62,8 @@
#define IMX415_VMAX IMX415_REG_24BIT(0x3024)
#define IMX415_VMAX_MAX 0xfffff
#define IMX415_HMAX IMX415_REG_16BIT(0x3028)
+#define IMX415_HMAX_MAX 0xffff
+#define IMX415_HMAX_MULTIPLIER 12
#define IMX415_SHR0 IMX415_REG_24BIT(0x3050)
#define IMX415_GAIN_PCG_0 IMX415_REG_16BIT(0x3090)
#define IMX415_AGAIN_MIN 0
@@ -459,7 +464,6 @@ static const struct imx415_clk_params im
/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */
static const struct imx415_reg imx415_mode_2_720[] = {
- { IMX415_HMAX, 0x07F0 },
{ IMX415_LANEMODE, IMX415_LANEMODE_2 },
{ IMX415_TCLKPOST, 0x006F },
{ IMX415_TCLKPREPARE, 0x002F },
@@ -474,7 +478,6 @@ static const struct imx415_reg imx415_mo
/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */
static const struct imx415_reg imx415_mode_2_1440[] = {
- { IMX415_HMAX, 0x042A },
{ IMX415_LANEMODE, IMX415_LANEMODE_2 },
{ IMX415_TCLKPOST, 0x009F },
{ IMX415_TCLKPREPARE, 0x0057 },
@@ -489,7 +492,6 @@ static const struct imx415_reg imx415_mo
/* all-pixel 4-lane 891 Mbps 30 Hz mode */
static const struct imx415_reg imx415_mode_4_891[] = {
- { IMX415_HMAX, 0x044C },
{ IMX415_LANEMODE, IMX415_LANEMODE_4 },
{ IMX415_TCLKPOST, 0x007F },
{ IMX415_TCLKPREPARE, 0x0037 },
@@ -507,39 +509,10 @@ struct imx415_mode_reg_list {
const struct imx415_reg *regs;
};
-/*
- * Mode : number of lanes, lane rate and frame rate dependent settings
- *
- * pixel_rate and hmax_pix are needed to calculate hblank for the v4l2 ctrl
- * interface. These values can not be found in the data sheet and should be
- * treated as virtual values. Use following table when adding new modes.
- *
- * lane_rate lanes fps hmax_pix pixel_rate
- *
- * 594 2 10.000 4400 99000000
- * 891 2 15.000 4400 148500000
- * 720 2 15.748 4064 144000000
- * 1782 2 30.000 4400 297000000
- * 2079 2 30.000 4400 297000000
- * 1440 2 30.019 4510 304615385
- *
- * 594 4 20.000 5500 247500000
- * 594 4 25.000 4400 247500000
- * 720 4 25.000 4400 247500000
- * 720 4 30.019 4510 304615385
- * 891 4 30.000 4400 297000000
- * 1440 4 30.019 4510 304615385
- * 1440 4 60.038 4510 609230769
- * 1485 4 60.000 4400 594000000
- * 1782 4 60.000 4400 594000000
- * 2079 4 60.000 4400 594000000
- * 2376 4 90.164 4392 891000000
- */
struct imx415_mode {
u64 lane_rate;
u32 lanes;
- u32 hmax_pix;
- u64 pixel_rate;
+ u32 hmax_min;
struct imx415_mode_reg_list reg_list;
};
@@ -548,8 +521,7 @@ static const struct imx415_mode supporte
{
.lane_rate = 720000000,
.lanes = 2,
- .hmax_pix = 4064,
- .pixel_rate = 144000000,
+ .hmax_min = 2032,
.reg_list = {
.num_of_regs = ARRAY_SIZE(imx415_mode_2_720),
.regs = imx415_mode_2_720,
@@ -558,8 +530,7 @@ static const struct imx415_mode supporte
{
.lane_rate = 1440000000,
.lanes = 2,
- .hmax_pix = 4510,
- .pixel_rate = 304615385,
+ .hmax_min = 1066,
.reg_list = {
.num_of_regs = ARRAY_SIZE(imx415_mode_2_1440),
.regs = imx415_mode_2_1440,
@@ -568,8 +539,7 @@ static const struct imx415_mode supporte
{
.lane_rate = 891000000,
.lanes = 4,
- .hmax_pix = 4400,
- .pixel_rate = 297000000,
+ .hmax_min = 1100,
.reg_list = {
.num_of_regs = ARRAY_SIZE(imx415_mode_4_891),
.regs = imx415_mode_4_891,
@@ -601,6 +571,7 @@ static const char *const imx415_test_pat
struct imx415 {
struct device *dev;
struct clk *clk;
+ unsigned long pixel_rate;
struct regulator_bulk_data supplies[ARRAY_SIZE(imx415_supply_names)];
struct gpio_desc *reset;
struct regmap *regmap;
@@ -614,6 +585,7 @@ struct imx415 {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *exposure;
@@ -845,6 +817,11 @@ static int imx415_s_ctrl(struct v4l2_ctr
case V4L2_CID_TEST_PATTERN:
return imx415_set_testpattern(sensor, ctrl->val);
+ case V4L2_CID_HBLANK:
+ return imx415_write(sensor, IMX415_HMAX,
+ (format->width + ctrl->val) /
+ IMX415_HMAX_MULTIPLIER);
+
default:
return -EINVAL;
}
@@ -858,12 +835,11 @@ static int imx415_ctrls_init(struct imx4
{
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl *ctrl;
- u64 pixel_rate = supported_modes[sensor->cur_mode].pixel_rate;
u64 lane_rate = supported_modes[sensor->cur_mode].lane_rate;
u32 exposure_max = IMX415_PIXEL_ARRAY_HEIGHT +
IMX415_PIXEL_ARRAY_VBLANK -
IMX415_EXPOSURE_OFFSET;
- u32 hblank;
+ u32 hblank_min, hblank_max;
unsigned int i;
int ret;
@@ -900,12 +876,14 @@ static int imx415_ctrls_init(struct imx4
IMX415_AGAIN_MAX, IMX415_AGAIN_STEP,
IMX415_AGAIN_MIN);
- hblank = supported_modes[sensor->cur_mode].hmax_pix -
- IMX415_PIXEL_ARRAY_WIDTH;
+ hblank_min = (supported_modes[sensor->cur_mode].hmax_min *
+ IMX415_HMAX_MULTIPLIER) - IMX415_PIXEL_ARRAY_WIDTH;
+ hblank_max = (IMX415_HMAX_MAX * IMX415_HMAX_MULTIPLIER) -
+ IMX415_PIXEL_ARRAY_WIDTH;
ctrl = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
- V4L2_CID_HBLANK, hblank, hblank, 1, hblank);
- if (ctrl)
- ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ V4L2_CID_HBLANK, hblank_min,
+ hblank_max, IMX415_HMAX_MULTIPLIER,
+ hblank_min);
sensor->vblank = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
V4L2_CID_VBLANK,
@@ -913,8 +891,9 @@ static int imx415_ctrls_init(struct imx4
IMX415_VMAX_MAX - IMX415_PIXEL_ARRAY_HEIGHT,
1, IMX415_PIXEL_ARRAY_VBLANK);
- v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE, pixel_rate,
- pixel_rate, 1, pixel_rate);
+ v4l2_ctrl_new_std(&sensor->ctrls, NULL, V4L2_CID_PIXEL_RATE,
+ sensor->pixel_rate, sensor->pixel_rate, 1,
+ sensor->pixel_rate);
sensor->hflip = v4l2_ctrl_new_std(&sensor->ctrls, &imx415_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
@@ -1410,6 +1389,17 @@ static int imx415_parse_hw_config(struct
"no valid sensor mode defined\n");
goto done_endpoint_free;
}
+ switch (inck) {
+ case 27000000:
+ case 37125000:
+ case 74250000:
+ sensor->pixel_rate = IMX415_PIXEL_RATE_74_25MHZ;
+ break;
+ case 24000000:
+ case 72000000:
+ sensor->pixel_rate = IMX415_PIXEL_RATE_72MHZ;
+ break;
+ }
lane_rate = supported_modes[sensor->cur_mode].lane_rate;
for (i = 0; i < ARRAY_SIZE(imx415_clk_params); ++i) {

View File

@ -0,0 +1,136 @@
From 0292614f8cd061f71f975dae7d74fe5324545321 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 2 Jan 2025 12:43:01 +0000
Subject: [PATCH] media: i2c: imx415: Link frequencies are not exclusive to num
lanes
The link frequencies are equally valid in 2 or 4 lane modes, but
they change the hmax_min value for the mode as the MIPI block
has to have sufficient time to send the pixel data for each line.
Remove the association with number of lanes, and add hmax_min
configuration for both lane options.
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx415.c | 49 +++++++++++++++++---------------------
1 file changed, 22 insertions(+), 27 deletions(-)
--- a/drivers/media/i2c/imx415.c
+++ b/drivers/media/i2c/imx415.c
@@ -462,9 +462,8 @@ static const struct imx415_clk_params im
},
};
-/* all-pixel 2-lane 720 Mbps 15.74 Hz mode */
-static const struct imx415_reg imx415_mode_2_720[] = {
- { IMX415_LANEMODE, IMX415_LANEMODE_2 },
+/* 720 Mbps CSI configuration */
+static const struct imx415_reg imx415_linkrate_720mbps[] = {
{ IMX415_TCLKPOST, 0x006F },
{ IMX415_TCLKPREPARE, 0x002F },
{ IMX415_TCLKTRAIL, 0x002F },
@@ -476,9 +475,8 @@ static const struct imx415_reg imx415_mo
{ IMX415_TLPX, 0x0027 },
};
-/* all-pixel 2-lane 1440 Mbps 30.01 Hz mode */
-static const struct imx415_reg imx415_mode_2_1440[] = {
- { IMX415_LANEMODE, IMX415_LANEMODE_2 },
+/* 1440 Mbps CSI configuration */
+static const struct imx415_reg imx415_linkrate_1440mbps[] = {
{ IMX415_TCLKPOST, 0x009F },
{ IMX415_TCLKPREPARE, 0x0057 },
{ IMX415_TCLKTRAIL, 0x0057 },
@@ -490,9 +488,8 @@ static const struct imx415_reg imx415_mo
{ IMX415_TLPX, 0x004F },
};
-/* all-pixel 4-lane 891 Mbps 30 Hz mode */
-static const struct imx415_reg imx415_mode_4_891[] = {
- { IMX415_LANEMODE, IMX415_LANEMODE_4 },
+/* 891 Mbps */
+static const struct imx415_reg imx415_linkrate_891mbps[] = {
{ IMX415_TCLKPOST, 0x007F },
{ IMX415_TCLKPREPARE, 0x0037 },
{ IMX415_TCLKTRAIL, 0x0037 },
@@ -511,8 +508,7 @@ struct imx415_mode_reg_list {
struct imx415_mode {
u64 lane_rate;
- u32 lanes;
- u32 hmax_min;
+ u32 hmax_min[2];
struct imx415_mode_reg_list reg_list;
};
@@ -520,29 +516,26 @@ struct imx415_mode {
static const struct imx415_mode supported_modes[] = {
{
.lane_rate = 720000000,
- .lanes = 2,
- .hmax_min = 2032,
+ .hmax_min = { 2032, 1066 },
.reg_list = {
- .num_of_regs = ARRAY_SIZE(imx415_mode_2_720),
- .regs = imx415_mode_2_720,
+ .num_of_regs = ARRAY_SIZE(imx415_linkrate_720mbps),
+ .regs = imx415_linkrate_720mbps,
},
},
{
.lane_rate = 1440000000,
- .lanes = 2,
- .hmax_min = 1066,
+ .hmax_min = { 1066, 533 },
.reg_list = {
- .num_of_regs = ARRAY_SIZE(imx415_mode_2_1440),
- .regs = imx415_mode_2_1440,
+ .num_of_regs = ARRAY_SIZE(imx415_linkrate_1440mbps),
+ .regs = imx415_linkrate_1440mbps,
},
},
{
.lane_rate = 891000000,
- .lanes = 4,
- .hmax_min = 1100,
+ .hmax_min = { 1100, 550 },
.reg_list = {
- .num_of_regs = ARRAY_SIZE(imx415_mode_4_891),
- .regs = imx415_mode_4_891,
+ .num_of_regs = ARRAY_SIZE(imx415_linkrate_891mbps),
+ .regs = imx415_linkrate_891mbps,
},
},
};
@@ -876,7 +869,7 @@ static int imx415_ctrls_init(struct imx4
IMX415_AGAIN_MAX, IMX415_AGAIN_STEP,
IMX415_AGAIN_MIN);
- hblank_min = (supported_modes[sensor->cur_mode].hmax_min *
+ hblank_min = (supported_modes[sensor->cur_mode].hmax_min[sensor->num_data_lanes == 2 ? 0 : 1] *
IMX415_HMAX_MULTIPLIER) - IMX415_PIXEL_ARRAY_WIDTH;
hblank_max = (IMX415_HMAX_MAX * IMX415_HMAX_MULTIPLIER) -
IMX415_PIXEL_ARRAY_WIDTH;
@@ -944,7 +937,11 @@ static int imx415_set_mode(struct imx415
return ret;
}
- return 0;
+ ret = imx415_write(sensor, IMX415_LANEMODE,
+ sensor->num_data_lanes == 2 ? IMX415_LANEMODE_2 :
+ IMX415_LANEMODE_4);
+
+ return ret;
}
static int imx415_setup(struct imx415 *sensor, struct v4l2_subdev_state *state)
@@ -1373,8 +1370,6 @@ static int imx415_parse_hw_config(struct
}
for (j = 0; j < ARRAY_SIZE(supported_modes); ++j) {
- if (sensor->num_data_lanes != supported_modes[j].lanes)
- continue;
if (bus_cfg.link_frequencies[i] * 2 !=
supported_modes[j].lane_rate)
continue;

View File

@ -0,0 +1,60 @@
From 87fc066350358ce45f5ad52424c8a2e351b1720c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 7 Jan 2025 12:05:41 +0000
Subject: [PATCH] dts: bcm2711: PL011 UARTs are actually r1p5
The ARM PL011 UART instances in BCM2711 are r1p5 spec, which means they
have 32-entry FIFOs. The correct periphid value for this is 0x00341011.
Thanks to N Buchwitz for pointing this out.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm/boot/dts/broadcom/bcm2711.dtsi | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -134,7 +134,7 @@
clocks = <&clocks BCM2835_CLOCK_UART>,
<&clocks BCM2835_CLOCK_VPU>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};
@@ -145,7 +145,7 @@
clocks = <&clocks BCM2835_CLOCK_UART>,
<&clocks BCM2835_CLOCK_VPU>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};
@@ -156,7 +156,7 @@
clocks = <&clocks BCM2835_CLOCK_UART>,
<&clocks BCM2835_CLOCK_VPU>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};
@@ -167,7 +167,7 @@
clocks = <&clocks BCM2835_CLOCK_UART>,
<&clocks BCM2835_CLOCK_VPU>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};
@@ -1155,6 +1155,7 @@
};
&uart0 {
+ arm,primecell-periphid = <0x00341011>;
interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
};

View File

@ -0,0 +1,43 @@
From 602be52637ecca0b247cf832c8a4ec345844d325 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 7 Jan 2025 12:09:48 +0000
Subject: [PATCH] dts: bcm2712: PL011 UARTs are actually r1p5
The ARM PL011 UART instances in BCM2712 are r1p5 spec, which means they
have 32-entry FIFOs. The correct periphid value for this is 0x00341011.
Thanks to N Buchwitz for pointing this out.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
@@ -190,7 +190,7 @@
clocks = <&clk_uart>,
<&clk_vpu>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};
@@ -201,7 +201,7 @@
clocks = <&clk_uart>,
<&clk_vpu>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};
@@ -212,7 +212,7 @@
clocks = <&clk_uart>,
<&clk_vpu>;
clock-names = "uartclk", "apb_pclk";
- arm,primecell-periphid = <0x00241011>;
+ arm,primecell-periphid = <0x00341011>;
status = "disabled";
};

View File

@ -0,0 +1,70 @@
From 7a4972f36a63eba4d862115265a7bf77ac1e4129 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 7 Jan 2025 12:11:10 +0000
Subject: [PATCH] dts: rp1: PL011 UARTs are actually r1p5
The ARM PL011 UART instances in RP1 are r1p5 spec, which means they
have 32-entry FIFOs. The correct periphid value for this is 0x00341011.
Thanks to N Buchwitz for pointing this out.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/rp1.dtsi | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/arch/arm64/boot/dts/broadcom/rp1.dtsi
+++ b/arch/arm64/boot/dts/broadcom/rp1.dtsi
@@ -69,7 +69,7 @@
<&rp1_dma RP1_DMA_UART0_RX>;
dma-names = "tx", "rx";
pinctrl-names = "default";
- arm,primecell-periphid = <0x00541011>;
+ arm,primecell-periphid = <0x00341011>;
uart-has-rtscts;
cts-event-workaround;
skip-init;
@@ -86,7 +86,7 @@
// <&rp1_dma RP1_DMA_UART1_RX>;
// dma-names = "tx", "rx";
pinctrl-names = "default";
- arm,primecell-periphid = <0x00541011>;
+ arm,primecell-periphid = <0x00341011>;
uart-has-rtscts;
cts-event-workaround;
skip-init;
@@ -103,7 +103,7 @@
// <&rp1_dma RP1_DMA_UART2_RX>;
// dma-names = "tx", "rx";
pinctrl-names = "default";
- arm,primecell-periphid = <0x00541011>;
+ arm,primecell-periphid = <0x00341011>;
uart-has-rtscts;
cts-event-workaround;
skip-init;
@@ -120,7 +120,7 @@
// <&rp1_dma RP1_DMA_UART3_RX>;
// dma-names = "tx", "rx";
pinctrl-names = "default";
- arm,primecell-periphid = <0x00541011>;
+ arm,primecell-periphid = <0x00341011>;
uart-has-rtscts;
cts-event-workaround;
skip-init;
@@ -137,7 +137,7 @@
// <&rp1_dma RP1_DMA_UART4_RX>;
// dma-names = "tx", "rx";
pinctrl-names = "default";
- arm,primecell-periphid = <0x00541011>;
+ arm,primecell-periphid = <0x00341011>;
uart-has-rtscts;
cts-event-workaround;
skip-init;
@@ -154,7 +154,7 @@
// <&rp1_dma RP1_DMA_UART5_RX>;
// dma-names = "tx", "rx";
pinctrl-names = "default";
- arm,primecell-periphid = <0x00541011>;
+ arm,primecell-periphid = <0x00341011>;
uart-has-rtscts;
cts-event-workaround;
skip-init;

View File

@ -0,0 +1,25 @@
From 4f7341263ebd6ab2ae805c8f27191d24abc05a62 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 8 Jan 2025 15:48:35 +0000
Subject: [PATCH] ASoC: pcm512x: Demote "No SCLK" to debug level
Designing a PCM512X-based soundcard with no external SCLK is a valid
choice supported by the driver. Don't alarm users with messages that
say "No SCLK, using BCLK: -2" - reclassify them as debug information.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
sound/soc/codecs/pcm512x.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -630,7 +630,7 @@ static int pcm512x_dai_startup_slave(str
struct regmap *regmap = pcm512x->regmap;
if (IS_ERR(pcm512x->sclk)) {
- dev_info(dev, "No SCLK, using BCLK: %ld\n",
+ dev_dbg(dev, "No SCLK, using BCLK: %ld\n",
PTR_ERR(pcm512x->sclk));
/* Disable reporting of missing SCLK as an error */

View File

@ -0,0 +1,58 @@
From 4111f4ede92b1f5bf869f87c66fc39151999c42f Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 8 Jan 2025 15:46:30 +0000
Subject: [PATCH] ASoC: allo-piano-dac-plus: Fix volume limiting
Controls which only exist when snd_soc_register_card returns can't be
modified before then. Move the setting of volume limits to just before
the end of the probe function.
Link: https://github.com/raspberrypi/linux/issues/6527
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
sound/soc/bcm/allo-piano-dac-plus.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)
--- a/sound/soc/bcm/allo-piano-dac-plus.c
+++ b/sound/soc/bcm/allo-piano-dac-plus.c
@@ -734,18 +734,6 @@ static int snd_allo_piano_dac_init(struc
if (digital_gain_0db_limit) {
int ret;
- ret = snd_soc_limit_volume(card, "Master Playback Volume",
- 207);
- if (ret < 0)
- dev_warn(card->dev, "Failed to set master volume limit: %d\n",
- ret);
-
- ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume",
- 207);
- if (ret < 0)
- dev_warn(card->dev, "Failed to set subwoofer volume limit: %d\n",
- ret);
-
//Set volume limit on both dacs
for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) {
char cname[256];
@@ -1000,6 +988,20 @@ static int snd_allo_piano_dac_probe(stru
if (ret < 0)
return dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n");
+ if (digital_gain_0db_limit) {
+ ret = snd_soc_limit_volume(card, "Master Playback Volume",
+ 207);
+ if (ret < 0)
+ dev_warn(card->dev, "Failed to set master volume limit: %d\n",
+ ret);
+
+ ret = snd_soc_limit_volume(card, "Subwoofer Playback Volume",
+ 207);
+ if (ret < 0)
+ dev_warn(card->dev, "Failed to set subwoofer volume limit: %d\n",
+ ret);
+ }
+
if ((mute_gpio[0]) && (mute_gpio[1]))
snd_allo_piano_gpio_mute(&snd_allo_piano_dac);

View File

@ -0,0 +1,53 @@
From 62c33972e3eb724d80179fb71b05e923920f0b0d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 8 Jan 2025 16:05:02 +0000
Subject: [PATCH] ASoC: allo-piano-dac-plus: Remove pointless code
The codec control Digital Playback Volume is one of the controls deleted
by the allo-piano-dac-plus driver. It is effectively replaced by the
soundcard controls Master Playback Volume and Subwoofer Playback Volume.
Delete the code that sets the volume limit on those codec controls - the
limits on the soundcard volume controls are sufficient.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
sound/soc/bcm/allo-piano-dac-plus.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)
--- a/sound/soc/bcm/allo-piano-dac-plus.c
+++ b/sound/soc/bcm/allo-piano-dac-plus.c
@@ -731,21 +731,6 @@ static int snd_allo_piano_dac_init(struc
mutex_init(&glb_ptr->lock);
- if (digital_gain_0db_limit) {
- int ret;
-
- //Set volume limit on both dacs
- for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) {
- char cname[256];
-
- sprintf(cname, "%s %s", codec_ctl_pfx[i], codec_ctl_name[0]);
- ret = snd_soc_limit_volume(card, cname, 207);
- if (ret < 0)
- dev_warn(card->dev, "Failed to set %s volume limit: %d\n",
- cname, ret);
- }
- }
-
// Remove codec controls
for (i = 0; i < ARRAY_SIZE(codec_ctl_pfx); i++) {
for (j = 0; j < ARRAY_SIZE(codec_ctl_name); j++) {
@@ -753,10 +738,7 @@ static int snd_allo_piano_dac_init(struc
sprintf(cname, "%s %s", codec_ctl_pfx[i], codec_ctl_name[j]);
kctl = snd_soc_card_get_kcontrol(card, cname);
- if (!kctl) {
- dev_err(rtd->card->dev, "Control %s not found\n",
- cname);
- } else {
+ if (kctl) {
kctl->vd[0].access =
SNDRV_CTL_ELEM_ACCESS_READWRITE;
snd_ctl_remove(card->snd_card, kctl);

View File

@ -0,0 +1,90 @@
From 301420a8cc44ee457670e015adc3a08cfc4531a9 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Wed, 8 Jan 2025 14:58:37 +0000
Subject: [PATCH] DT: bcm2712: override supports-cqe to a cell
We want to be able to control the interop surface exposed by Command
Queueing across bcm2712 products to a more restrictive default, with
selectable disable and permissive behaviour.
Changing the bool to a cell lets it relay a tristate value.
Also add the override parameter to CM5 as CM5-lite may interface with
arbitrary eMMC or SD cards.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
arch/arm/boot/dts/overlays/README | 11 ++++++++---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 4 ++--
arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 3 ++-
arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 +-
4 files changed, 13 insertions(+), 7 deletions(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -405,9 +405,14 @@ Params:
non-lite SKU of CM4).
(default "on")
- sd_cqe Set to "off" to disable Command Queueing if you
- have an incompatible Class A2 SD card
- (Pi 5 only, default "on")
+ sd_cqe Modify Command Queuing behaviour on the main SD
+ interface. Legal values are:
+ 0: disable CQ
+ 1: allow CQ for known-good SD A2 cards, and all
+ eMMC cards
+ 2: allow CQ for all SD A2 cards that aren't
+ known-bad, and all eMMC cards.
+ (2712 only, default "1")
sd_overclock Clock (in MHz) to use when the MMC framework
requests 50MHz
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -365,7 +365,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g
sd-uhs-sdr50;
sd-uhs-ddr50;
sd-uhs-sdr104;
- supports-cqe;
+ supports-cqe = <1>;
cd-gpios = <&gio_aon 5 GPIO_ACTIVE_LOW>;
//no-1-8-v;
status = "okay";
@@ -745,6 +745,6 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
/ {
__overrides__ {
- sd_cqe = <&sdio1>, "supports-cqe?";
+ sd_cqe = <&sdio1>, "supports-cqe:0";
};
};
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
@@ -339,7 +339,7 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_g
mmc-hs400-1_8v;
mmc-hs400-enhanced-strobe;
broken-cd;
- supports-cqe;
+ supports-cqe = <1>;
status = "okay";
};
@@ -752,5 +752,6 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
<&ant2>, "output-low?=on";
noanthogs = <&ant1>,"status=disabled",
<&ant2>, "status=disabled";
+ sd_cqe = <&sdio1>, "supports-cqe:0";
};
};
--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
@@ -1210,7 +1210,7 @@
clocks = <&clk_emmc2>;
sdhci-caps-mask = <0x0000C000 0x0>;
sdhci-caps = <0x0 0x0>;
- supports-cqe;
+ supports-cqe = <1>;
mmc-ddr-3_3v;
status = "disabled";
};

View File

@ -0,0 +1,57 @@
From d70a60eb03ae4fc687b91b5f6c4684000be21c5f Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Wed, 8 Jan 2025 15:09:53 +0000
Subject: [PATCH] mmc: sd: filter card CQ support based on an allow-list
We have found that many SD cards in the field, even of the same make and
model, have latent bugs in their CQ implementation. Some product lines
have fewer bugs with newer manufacture dates, but this is not a
guarantee that a particular card is at a particular firmware revision
level.
Many of these bugs lead to card hangs or data corruption. Add a quirk to
mark a card as having a tested, working CQ implementation and ignore the
capability if absent.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/core/card.h | 5 +++++
drivers/mmc/core/sd.c | 4 ++++
include/linux/mmc/card.h | 1 +
3 files changed, 10 insertions(+)
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -292,4 +292,9 @@ static inline int mmc_card_broken_sd_pow
return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY;
}
+static inline int mmc_card_working_sd_cq(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_WORKING_SD_CQ;
+}
+
#endif
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1506,6 +1506,10 @@ cont:
goto free_card;
}
+ /* Disallow command queueing on unvetted cards */
+ if (!mmc_card_working_sd_cq(card))
+ card->ext_csd.cmdq_support = false;
+
/* Enable command queueing if supported */
if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
/*
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -297,6 +297,7 @@ struct mmc_card {
#define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */
#define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */
#define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */
+#define MMC_QUIRK_WORKING_SD_CQ (1<<30) /* SD card has known-good CQ implementation */
#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */
bool written_flag; /* Indicates eMMC has been written since power on */

View File

@ -0,0 +1,41 @@
From eb4d8ffb2b007963662be7eca88baf0e5c358bd6 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Wed, 8 Jan 2025 15:18:33 +0000
Subject: [PATCH] mmc: set MMC_QUIRK_KNOWN_WORKING_SD_CQ on Raspberry Pi class
A2 cards
These cards have a known-good CQ implementation and are based on a
Longsys product. Add the MANFID for Longsys SD, and the particular CID
details for the Pi card.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/core/card.h | 1 +
drivers/mmc/core/quirks.h | 6 ++++++
2 files changed, 7 insertions(+)
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -90,6 +90,7 @@ struct mmc_fixup {
#define CID_MANFID_KINGSTON 0x70
#define CID_MANFID_HYNIX 0x90
#define CID_MANFID_KINGSTON_SD 0x9F
+#define CID_MANFID_LONGSYS_SD 0xAD
#define CID_MANFID_NUMONYX 0xFE
#define END_FIXUP { NULL }
--- a/drivers/mmc/core/quirks.h
+++ b/drivers/mmc/core/quirks.h
@@ -66,6 +66,12 @@ static const struct mmc_fixup __maybe_un
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
+ /* SD A2 allow-list - only trust CQ on these cards */
+ /* Raspberry Pi A2 cards */
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_LONGSYS_SD, 0x4c53, CID_YEAR_ANY, CID_MONTH_ANY,
+ cid_rev(1, 0, 0, 0), -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
+ MMC_QUIRK_WORKING_SD_CQ, EXT_CSD_REV_ANY),
+
END_FIXUP
};

View File

@ -0,0 +1,94 @@
From e72f42ebc9a236c023f8027a37c9351d58e28b05 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Wed, 8 Jan 2025 16:02:27 +0000
Subject: [PATCH] mmc: use downstream DT property to modify CQE and/or SD CQ
behaviour
Implement a tristate-style option for "supports-cqe". If the property is
absent or zero, disable CQ completely. For 1, enable CQ unconditionally
for eMMC cards, and known-good SD cards. For 2, enable for eMMC cards,
and all SD cards that are not known-bad.
The sdhci-brcmstb driver needs to know about the tristate as its probe
sequence would otherwise override a disable in mmc_of_parse().
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
---
drivers/mmc/core/host.c | 11 ++++++++++-
drivers/mmc/core/sd.c | 4 ++--
drivers/mmc/host/sdhci-brcmstb.c | 6 ++++--
include/linux/mmc/host.h | 1 +
4 files changed, 17 insertions(+), 5 deletions(-)
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -275,7 +275,7 @@ EXPORT_SYMBOL(mmc_of_parse_clk_phase);
int mmc_of_parse(struct mmc_host *host)
{
struct device *dev = host->parent;
- u32 bus_width, drv_type, cd_debounce_delay_ms;
+ u32 bus_width, drv_type, cd_debounce_delay_ms, cq_allow;
int ret;
if (!dev || !dev_fwnode(dev))
@@ -410,6 +410,15 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
+ cq_allow = 0;
+ /*
+ * Downstream property - if a u32 and 2 instead of a bool,
+ * trust most A2 SD cards claiming CQ support.
+ */
+ device_property_read_u32(dev, "supports-cqe", &cq_allow);
+ if (cq_allow == 2)
+ host->caps2 |= MMC_CAP2_SD_CQE_PERMISSIVE;
+
/* Must be after "non-removable" check */
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
if (host->caps & MMC_CAP_NONREMOVABLE)
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1506,8 +1506,8 @@ cont:
goto free_card;
}
- /* Disallow command queueing on unvetted cards */
- if (!mmc_card_working_sd_cq(card))
+ /* Disallow command queueing on unvetted cards unless overridden */
+ if (!(host->caps2 & MMC_CAP2_SD_CQE_PERMISSIVE) && !mmc_card_working_sd_cq(card))
card->ext_csd.cmdq_support = false;
/* Enable command queueing if supported */
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -511,7 +511,7 @@ static int sdhci_brcmstb_probe(struct pl
struct sdhci_pltfm_host *pltfm_host;
const struct of_device_id *match;
struct sdhci_brcmstb_priv *priv;
- u32 actual_clock_mhz;
+ u32 actual_clock_mhz, cqe;
struct sdhci_host *host;
struct resource *iomem;
bool no_pinctrl = false;
@@ -540,7 +540,9 @@ static int sdhci_brcmstb_probe(struct pl
pltfm_host->clk = clk;
priv = sdhci_pltfm_priv(pltfm_host);
- if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
+ cqe = 0;
+ device_property_read_u32(&pdev->dev, "supports-cqe", &cqe);
+ if (cqe > 0) {
priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
}
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -427,6 +427,7 @@ struct mmc_host {
#define MMC_CAP2_CRYPTO 0
#endif
#define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */
+#define MMC_CAP2_SD_CQE_PERMISSIVE (1 << 31) /* Ignore allow-list for CQ capable SD card detection */
int fixed_drv_type; /* fixed driver type for non-removable media */

View File

@ -0,0 +1,38 @@
From e56aa0bd2b552daa4349a7eb2e6b0dec81d3e5cc Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 9 Jan 2025 16:40:25 +0000
Subject: [PATCH] misc: rp1-pio: Handle probe errors
Ensure that rp1_pio_open fails if the device failed to probe.
Link: https://github.com/raspberrypi/linux/issues/6593
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/misc/rp1-pio.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
--- a/drivers/misc/rp1-pio.c
+++ b/drivers/misc/rp1-pio.c
@@ -1014,6 +1014,9 @@ struct rp1_pio_client *rp1_pio_open(void
{
struct rp1_pio_client *client;
+ if (!g_pio)
+ return ERR_PTR(-ENOENT);
+
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return ERR_PTR(-ENOMEM);
@@ -1265,9 +1268,8 @@ static int rp1_pio_probe(struct platform
return dev_err_probe(dev, pdev->id, "alias is missing\n");
fw = devm_rp1_firmware_get(dev, dev->of_node);
- if (IS_ERR(fw))
- return PTR_ERR(fw);
-
+ if (IS_ERR_OR_NULL(fw))
+ return dev_err_probe(dev, -ENOENT, "failed to contact RP1 firmware\n");
ret = rp1_firmware_get_feature(fw, FOURCC_PIO, &op_base, &op_count);
if (ret < 0)
return ret;

View File

@ -0,0 +1,84 @@
From dafde0ac8b6d4b21578a677c8afad8714af47aaf Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 9 Jan 2025 16:33:37 +0000
Subject: [PATCH] firmware: rp1: Simplify rp1_firmware_get
Simplify the implementation of rp1_firmware_get, requiring its clients
to have a valid 'firmware' property. Also make it return NULL on error.
Link: https://github.com/raspberrypi/linux/issues/6593
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/firmware/rp1.c | 36 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 21 deletions(-)
--- a/drivers/firmware/rp1.c
+++ b/drivers/firmware/rp1.c
@@ -159,42 +159,36 @@ struct rp1_firmware *rp1_firmware_get(st
struct device_node *fwnode;
struct rp1_firmware *fw;
- if (client) {
- fwnode = of_parse_phandle(client, "firmware", 0);
- if (!fwnode)
- fwnode = of_get_parent(client);
- if (fwnode && !of_device_is_compatible(fwnode, match)) {
- of_node_put(fwnode);
- fwnode = NULL;
- }
- }
-
- if (!fwnode)
- fwnode = of_find_matching_node(NULL, rp1_firmware_of_match);
-
+ if (!client)
+ return NULL;
+ fwnode = of_parse_phandle(client, "firmware", 0);
if (!fwnode)
- return ERR_PTR(-ENOENT);
+ return NULL;
+ if (!of_device_is_compatible(fwnode, match)) {
+ of_node_put(fwnode);
+ return NULL;
+ }
pdev = of_find_device_by_node(fwnode);
of_node_put(fwnode);
if (!pdev)
- return ERR_PTR(-EPROBE_DEFER);
+ goto err_exit;
fw = platform_get_drvdata(pdev);
if (!fw)
- goto err_defer;
+ goto err_exit;
if (!kref_get_unless_zero(&fw->consumers))
- goto err_defer;
+ goto err_exit;
put_device(&pdev->dev);
return fw;
-err_defer:
+err_exit:
put_device(&pdev->dev);
- return ERR_PTR(-EPROBE_DEFER);
+ return NULL;
}
EXPORT_SYMBOL_GPL(rp1_firmware_get);
@@ -210,8 +204,8 @@ struct rp1_firmware *devm_rp1_firmware_g
int ret;
fw = rp1_firmware_get(client);
- if (IS_ERR(fw))
- return fw;
+ if (!fw)
+ return NULL;
ret = devm_add_action_or_reset(dev, devm_rp1_firmware_put, fw);
if (ret)

View File

@ -0,0 +1,44 @@
From d06cb3534b6553a1f76bef2ddaf833e23dc12a4c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Fri, 10 Jan 2025 15:45:11 +0000
Subject: [PATCH] dts: bcm2711: Don't mark timer regs unconfigured
The DT property arm,cpu-registers-not-fw-configured tells the kernel
that the ARM architectural timer has not been configured by the
firmware. This prevents the use of a vDSO - a faster alternative to a
syscall for some common kernel operations.
However, on Pi 4 the firmware does configure the timer, so this property
is unnecessary. Delete it.
Also remove it from the bcm2712.dtsi where it should never have been,
since it is only relevant to 32-bit ARM kernels.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm/boot/dts/broadcom/bcm2711.dtsi | 2 --
arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 2 --
2 files changed, 4 deletions(-)
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -451,8 +451,6 @@
IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
IRQ_TYPE_LEVEL_LOW)>;
- /* This only applies to the ARMv7 stub */
- arm,cpu-registers-not-fw-configured;
};
cpus: cpus {
--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
@@ -741,8 +741,6 @@
IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
IRQ_TYPE_LEVEL_LOW)>;
- /* This only applies to the ARMv7 stub */
- arm,cpu-registers-not-fw-configured;
};
cpus: cpus {

View File

@ -0,0 +1,29 @@
From dfff38316c1284c30c68d02cc424bad0562cf253 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Fri, 10 Jan 2025 16:33:13 +0000
Subject: [PATCH] mmc: bcm2835-sdhost Observe SWIOTLB memory limit
Make sure the sdhost driver doesn't use requests bigger than SWIOTLB
can handle.
Copied from [1].
Link: https://github.com/raspberrypi/linux/issues/6589
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
[1] d4dd9bccf485 ("mmc: bcm2835: Take SWIOTLB memory size limitation
into account")
---
drivers/mmc/host/bcm2835-sdhost.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mmc/host/bcm2835-sdhost.c
+++ b/drivers/mmc/host/bcm2835-sdhost.c
@@ -1971,7 +1971,7 @@ int bcm2835_sdhost_add_host(struct platf
}
mmc->max_segs = 128;
- mmc->max_req_size = 524288;
+ mmc->max_req_size = min_t(size_t, 524288, dma_max_mapping_size(&pdev->dev));
mmc->max_seg_size = mmc->max_req_size;
mmc->max_blk_size = 512;
mmc->max_blk_count = 65535;

View File

@ -0,0 +1,31 @@
From a73ecafc5532e31b184220149cc2863f625700bf Mon Sep 17 00:00:00 2001
From: Naushir Patuck <naush@raspberrypi.com>
Date: Wed, 15 Jan 2025 09:46:25 +0000
Subject: [PATCH] drivers: media: pisp_be: Add support for YUV422 planar format
List V4L2_PIX_FMT_YUV422P as supported by the PiSP backend hardware.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
.../platform/raspberrypi/pisp_be/pisp_be_formats.h | 10 ++++++++++
1 file changed, 10 insertions(+)
--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h
+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h
@@ -129,6 +129,16 @@ static const struct pisp_be_format suppo
.colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
.colorspace_default = V4L2_COLORSPACE_SMPTE170M,
},
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ /* 128 alignment to ensure U/V planes are 64 byte aligned. */
+ .align = 128,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5), P3(0.5) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
/* Multiplane YUV formats */
{
.fourcc = V4L2_PIX_FMT_YUV420M,

View File

@ -0,0 +1,82 @@
From a452251cc286f2799969f047698c76fe3d7862b9 Mon Sep 17 00:00:00 2001
From: Naushir Patuck <naush@raspberrypi.com>
Date: Thu, 16 Jan 2025 10:13:57 +0000
Subject: [PATCH] drivers: media: pisp_be: Remove unused fields in struct
pisp_be_config
These fields should not be set by either the user or the kernel driver
so remove them. Replace them with padding bytes to maintain backward
compatibility with existing userland applications.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
---
.../linux/media/raspberrypi/pisp_be_config.h | 42 ++-----------------
1 file changed, 4 insertions(+), 38 deletions(-)
--- a/include/uapi/linux/media/raspberrypi/pisp_be_config.h
+++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
@@ -716,13 +716,6 @@ struct pisp_be_hog_buffer_config {
/**
* struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration
*
- * @input_buffer: Input buffer addresses
- * @tdn_input_buffer: TDN input buffer addresses
- * @stitch_input_buffer: Stitch input buffer addresses
- * @tdn_output_buffer: TDN output buffer addresses
- * @stitch_output_buffer: Stitch output buffer addresses
- * @output_buffer: Output buffers addresses
- * @hog_buffer: HOG buffer addresses
* @global: Global PiSP configuration
* @input_format: Input image format
* @decompress: Decompress configuration
@@ -761,28 +754,10 @@ struct pisp_be_hog_buffer_config {
* @output_format: Output format configuration
* @hog: HOG configuration
* @axi: AXI bus configuration
- * @lsc_extra: LSC extra info
- * @cac_extra: CAC extra info
- * @downscale_extra: Downscaler extra info
- * @resample_extra: Resample extra info
- * @crop: Crop configuration
- * @hog_format: HOG format info
- * @dirty_flags_bayer: Bayer enable dirty flags
- * (:c:type:`pisp_be_bayer_enable`)
- * @dirty_flags_rgb: RGB enable dirty flags
- * (:c:type:`pisp_be_rgb_enable`)
- * @dirty_flags_extra: Extra dirty flags
*/
struct pisp_be_config {
- /* I/O configuration: */
- struct pisp_be_input_buffer_config input_buffer;
- struct pisp_be_tdn_input_buffer_config tdn_input_buffer;
- struct pisp_be_stitch_input_buffer_config stitch_input_buffer;
- struct pisp_be_tdn_output_buffer_config tdn_output_buffer;
- struct pisp_be_stitch_output_buffer_config stitch_output_buffer;
- struct pisp_be_output_buffer_config
- output_buffer[PISP_BACK_END_NUM_OUTPUTS];
- struct pisp_be_hog_buffer_config hog_buffer;
+ /* For backward compatibility */
+ uint8_t pad0[112];
/* Processing configuration: */
struct pisp_be_global_config global;
struct pisp_image_format_config input_format;
@@ -823,17 +798,8 @@ struct pisp_be_config {
output_format[PISP_BACK_END_NUM_OUTPUTS];
struct pisp_be_hog_config hog;
struct pisp_be_axi_config axi;
- /* Non-register fields: */
- struct pisp_be_lsc_extra lsc_extra;
- struct pisp_be_cac_extra cac_extra;
- struct pisp_be_downscale_extra
- downscale_extra[PISP_BACK_END_NUM_OUTPUTS];
- struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS];
- struct pisp_be_crop_config crop;
- struct pisp_image_format_config hog_format;
- __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */
- __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */
- __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */
+ /* For backward compatibility */
+ uint8_t pad1[84];
} __attribute__((packed));
/**

View File

@ -0,0 +1,163 @@
From 5b958efc20d381ee103103df5df0c88dc02ada18 Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Thu, 16 Jan 2025 11:08:25 +0000
Subject: [PATCH] media: imx219: Adjust PLL settings based on the number of
MIPI lanes
Commit ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation")
added support for device tree to allow configuration of the sensor to
use 4 lanes with a link frequency of 363MHz, and amended the advertised
pixel rate to 280.8MPix/s.
However it didn't change any of the PLL settings, so actually it would
have been running effectively overclocked in the MIPI block, and with
the frame rate and exposure calculations being wrong.
The pixel rate and link frequency advertised were taken from the "Clock
Setting Example" section of the datasheet. However those are based on an
external clock of 12MHz, and are unachievable with a clock of 24MHz (it
seems PREPLLCLK_VT_DIV and PREPLLCK_OP_DIV can ONLY be set via the
automatic configuration doumented in "9-1-2 EXCK_FREQ setting depend on
INCK frequency).
Dropping all support for the 363MHz link frequency would cause problems
for existing users, so allow it from device tree, but log a warning that
the requested value is not being truly applied.
Fixes: ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation")
Co-developed-by: Peyton Howe <peyton.howe@bellsouth.net>
Signed-off-by: Peyton Howe <peyton.howe@bellsouth.net>
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
drivers/media/i2c/imx219.c | 83 +++++++++++++++++++++++++++++---------
1 file changed, 64 insertions(+), 19 deletions(-)
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -148,10 +148,11 @@
/* Pixel rate is fixed for all the modes */
#define IMX219_PIXEL_RATE 182400000
-#define IMX219_PIXEL_RATE_4LANE 280800000
+#define IMX219_PIXEL_RATE_4LANE 281600000
#define IMX219_DEFAULT_LINK_FREQ 456000000
-#define IMX219_DEFAULT_LINK_FREQ_4LANE 363000000
+#define IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED 363000000
+#define IMX219_DEFAULT_LINK_FREQ_4LANE 364000000
/* IMX219 native and active pixel array size. */
#define IMX219_NATIVE_WIDTH 3296U
@@ -224,15 +225,6 @@ static const struct cci_reg_sequence imx
{ CCI_REG8(0x30eb), 0x05 },
{ CCI_REG8(0x30eb), 0x09 },
- /* PLL Clock Table */
- { IMX219_REG_VTPXCK_DIV, 5 },
- { IMX219_REG_VTSYCK_DIV, 1 },
- { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */
- { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */
- { IMX219_REG_PLL_VT_MPY, 57 },
- { IMX219_REG_OPSYCK_DIV, 1 },
- { IMX219_REG_PLL_OP_MPY, 114 },
-
/* Undocumented registers */
{ CCI_REG8(0x455e), 0x00 },
{ CCI_REG8(0x471e), 0x4b },
@@ -316,6 +308,34 @@ static const struct cci_reg_sequence raw
{ IMX219_REG_OPPXCK_DIV, 10 },
};
+static const struct cci_reg_sequence imx219_2lane_regs[] = {
+ /* PLL Clock Table */
+ { IMX219_REG_VTPXCK_DIV, 5 },
+ { IMX219_REG_VTSYCK_DIV, 1 },
+ { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */
+ { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */
+ { IMX219_REG_PLL_VT_MPY, 57 },
+ { IMX219_REG_OPSYCK_DIV, 1 },
+ { IMX219_REG_PLL_OP_MPY, 114 },
+
+ /* 2-Lane CSI Mode */
+ { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_2_LANE_MODE },
+};
+
+static const struct cci_reg_sequence imx219_4lane_regs[] = {
+ /* PLL Clock Table */
+ { IMX219_REG_VTPXCK_DIV, 5 },
+ { IMX219_REG_VTSYCK_DIV, 1 },
+ { IMX219_REG_PREPLLCK_VT_DIV, 3 }, /* 0x03 = AUTO set */
+ { IMX219_REG_PREPLLCK_OP_DIV, 3 }, /* 0x03 = AUTO set */
+ { IMX219_REG_PLL_VT_MPY, 88 },
+ { IMX219_REG_OPSYCK_DIV, 1 },
+ { IMX219_REG_PLL_OP_MPY, 91 },
+
+ /* 4-Lane CSI Mode */
+ { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_4_LANE_MODE },
+};
+
static const s64 imx219_link_freq_menu[] = {
IMX219_DEFAULT_LINK_FREQ,
};
@@ -941,9 +961,11 @@ static int imx219_get_selection(struct v
static int imx219_configure_lanes(struct imx219 *imx219)
{
- return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE,
- imx219->lanes == 2 ? IMX219_CSI_2_LANE_MODE :
- IMX219_CSI_4_LANE_MODE, NULL);
+ /* Write the appropriate PLL settings for the number of MIPI lanes */
+ return cci_multi_reg_write(imx219->regmap,
+ imx219->lanes == 2 ? imx219_2lane_regs : imx219_4lane_regs,
+ imx219->lanes == 2 ? ARRAY_SIZE(imx219_2lane_regs) :
+ ARRAY_SIZE(imx219_4lane_regs), NULL);
};
static int imx219_start_streaming(struct imx219 *imx219,
@@ -1334,6 +1356,7 @@ static int imx219_check_hwcfg(struct dev
.bus_type = V4L2_MBUS_CSI2_DPHY
};
int ret = -EINVAL;
+ bool link_frequency_valid = false;
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
if (!endpoint) {
@@ -1360,11 +1383,33 @@ static int imx219_check_hwcfg(struct dev
goto error_out;
}
- if (ep_cfg.nr_of_link_frequencies != 1 ||
- (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?
- IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {
- dev_err(dev, "Link frequency not supported: %lld\n",
- ep_cfg.link_frequencies[0]);
+ if (ep_cfg.nr_of_link_frequencies == 1) {
+ switch (imx219->lanes) {
+ case 2:
+ if (ep_cfg.link_frequencies[0] ==
+ IMX219_DEFAULT_LINK_FREQ)
+ link_frequency_valid = true;
+ break;
+ case 4:
+ if (ep_cfg.link_frequencies[0] ==
+ IMX219_DEFAULT_LINK_FREQ_4LANE)
+ link_frequency_valid = true;
+ else if (ep_cfg.link_frequencies[0] ==
+ IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED) {
+ dev_warn(dev, "Link frequency of %d not supported, but has been incorrectly advertised previously\n",
+ IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED);
+ dev_warn(dev, "Using link frequency of %d\n",
+ IMX219_DEFAULT_LINK_FREQ_4LANE);
+ link_frequency_valid = true;
+ }
+ break;
+ }
+ }
+
+ if (!link_frequency_valid) {
+ dev_err_probe(dev, -EINVAL,
+ "Link frequency not supported: %lld\n",
+ ep_cfg.link_frequencies[0]);
goto error_out;
}

View File

@ -0,0 +1,55 @@
From e3297f3fbffdaec8076c00167261f504bb2c64b6 Mon Sep 17 00:00:00 2001
From: Peyton Howe <peyton.howe@bellsouth.net>
Date: Sat, 4 Jan 2025 15:15:33 -0500
Subject: [PATCH] IMX219: Add 4-lane option to the device tree overlay
Signed-off-by: Peyton Howe <peyton.howe@bellsouth.net>
---
arch/arm/boot/dts/overlays/README | 2 ++
arch/arm/boot/dts/overlays/imx219-overlay.dts | 17 +++++++++++++++++
2 files changed, 19 insertions(+)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -2757,6 +2757,8 @@ Params: rotation Mounting
cam0 Adopt the default configuration for CAM0 on a
Compute Module (CSI0, i2c_vc, and cam0_reg).
vcm Configure a VCM focus drive on the sensor.
+ 4lane Enable 4 CSI2 lanes. This requires a Compute
+ Module (1, 3, 4, or 5) or Pi 5.
Name: imx258
--- a/arch/arm/boot/dts/overlays/imx219-overlay.dts
+++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts
@@ -65,6 +65,22 @@
};
};
+ fragment@201 {
+ target = <&csi_ep>;
+ __dormant__ {
+ data-lanes = <1 2 3 4>;
+ };
+ };
+
+ fragment@202 {
+ target = <&cam_endpoint>;
+ __dormant__ {
+ data-lanes = <1 2 3 4>;
+ link-frequencies =
+ /bits/ 64 <363000000>;
+ };
+ };
+
__overrides__ {
rotation = <&cam_node>,"rotation:0";
orientation = <&cam_node>,"orientation:0";
@@ -77,6 +93,7 @@
<&vcm>, "VANA-supply:0=", <&cam0_reg>;
vcm = <&vcm>, "status=okay",
<&cam_node>,"lens-focus:0=", <&vcm>;
+ 4lane = <0>, "+201+202";
};
};

View File

@ -0,0 +1,40 @@
From 11381ac246576bc84dfc28f6cdd8030305c605aa Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Mon, 20 Jan 2025 11:53:04 +0000
Subject: [PATCH] dtoverlays: waveshare-panel: Disable new touch controller by
default
Commit e442e5c1ab6b ("arch:arm:boot:dts:overlays: Added waveshare 13.3inch
panel support") added an extra touch controller for the new panels.
On systems with old panels, it ends up spamming the kernel log as that
touch controller isn't there to respond.
Fixes: e442e5c1ab6b ("arch:arm:boot:dts:overlays: Added waveshare 13.3inch panel support")
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
.../dts/overlays/vc4-kms-dsi-waveshare-panel-overlay.dts | 7 +++++--
1 file changed, 5 insertions(+), 2 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
@@ -55,6 +55,7 @@
touch2: ilitek@41 {
compatible = "ilitek,ili251x";
reg = <0x41>;
+ status = "disabled";
};
};
};
@@ -125,8 +126,10 @@
<&touch>, "touchscreen-inverted-x?",
<&touch>, "touchscreen-inverted-y?";
8_8_inch = <&panel>, "compatible=waveshare,8.8inch-panel";
- 13_3_inch_4lane = <&panel>, "compatible=waveshare,13.3inch-4lane-panel";
- 13_3_inch_2lane = <&panel>, "compatible=waveshare,13.3inch-2lane-panel";
+ 13_3_inch_4lane = <&panel>, "compatible=waveshare,13.3inch-4lane-panel",
+ <&touch2>, "status=okay";
+ 13_3_inch_2lane = <&panel>, "compatible=waveshare,13.3inch-2lane-panel",
+ <&touch2>, "status=okay";
i2c1 = <&i2c_frag>, "target:0=",<&i2c1>,
<0>, "-3-4+5";
disable_touch = <&touch>, "status=disabled";

View File

@ -0,0 +1,325 @@
From ba9883e3b667e4f1fbeacc4346f6e9179a3a5479 Mon Sep 17 00:00:00 2001
From: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
Date: Mon, 20 Jan 2025 11:20:48 +0000
Subject: [PATCH] drm: rp1: rp1-dpi: Add "rgb_order" property (to match VC4
DPI)
As on VC4, the OF property overrides the order implied by media
bus format. Only 4 of the 6 possible orders are supported. New
add-on hardware designs should not rely on this "legacy" feature.
Signed-off-by: Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>
---
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c | 15 ++
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h | 8 +
drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c | 191 ++++++++++++++---------
3 files changed, 143 insertions(+), 71 deletions(-)
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
@@ -292,6 +292,7 @@ static int rp1dpi_platform_probe(struct
struct device *dev = &pdev->dev;
struct rp1_dpi *dpi;
struct drm_bridge *bridge = NULL;
+ const char *rgb_order = NULL;
struct drm_panel *panel;
int i, j, ret;
@@ -353,6 +354,20 @@ static int rp1dpi_platform_probe(struct
if (ret)
goto done_err;
+ dpi->rgb_order_override = RP1DPI_ORDER_UNCHANGED;
+ if (!of_property_read_string(dev->of_node, "rgb_order", &rgb_order)) {
+ if (!strcmp(rgb_order, "rgb"))
+ dpi->rgb_order_override = RP1DPI_ORDER_RGB;
+ else if (!strcmp(rgb_order, "bgr"))
+ dpi->rgb_order_override = RP1DPI_ORDER_BGR;
+ else if (!strcmp(rgb_order, "grb"))
+ dpi->rgb_order_override = RP1DPI_ORDER_GRB;
+ else if (!strcmp(rgb_order, "brg"))
+ dpi->rgb_order_override = RP1DPI_ORDER_BRG;
+ else
+ DRM_ERROR("Invalid dpi order %s - ignored\n", rgb_order);
+ }
+
/* Check if PIO can snoop on or override DPI's GPIO1 */
dpi->gpio1_used = false;
for (i = 0; !dpi->gpio1_used; i++) {
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
@@ -25,6 +25,13 @@
#define RP1DPI_CLK_PLLCORE 2
#define RP1DPI_NUM_CLOCKS 3
+/* Codes (in LE byte order) used for S/W permutation */
+#define RP1DPI_ORDER_UNCHANGED 0
+#define RP1DPI_ORDER_RGB 0x020100
+#define RP1DPI_ORDER_BGR 0x000102
+#define RP1DPI_ORDER_GRB 0x020001
+#define RP1DPI_ORDER_BRG 0x010002
+
/* ---------------------------------------------------------------------- */
struct rp1_dpi {
@@ -45,6 +52,7 @@ struct rp1_dpi {
u32 bus_fmt;
bool de_inv, clk_inv;
bool dpi_running, pipe_enabled;
+ unsigned int rgb_order_override;
struct completion finished;
/* Experimental stuff for interlace follows */
--- a/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
+++ b/drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi_hw.c
@@ -223,12 +223,90 @@ int rp1dpi_hw_busy(struct rp1_dpi *dpi)
return (rp1dpi_hw_read(dpi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0;
}
-/* Table of supported input (in-memory/DMA) pixel formats. */
+/*
+ * Table of supported input (in-memory/DMA) pixel formats.
+ *
+ * RP1 DPI describes RGB components in terms of their MS bit position, a 10-bit
+ * left-aligned bit-mask, and an optional right-shift-and-OR used for scaling.
+ * To make it easier to permute R, G and B components, we re-pack these fields
+ * into 32-bit code-words, which don't themselves correspond to any register.
+ */
+
+#define RGB_CODE(scale, shift, mask) (((scale) << 24) | ((shift) << 16) | (mask))
+#define RGB_SCALE(c) ((c) >> 24)
+#define RGB_SHIFT(c) (((c) >> 16) & 31)
+#define RGB_MASK(c) ((c) & 0x3ff)
+
struct rp1dpi_ipixfmt {
- u32 format; /* DRM format code */
- u32 mask; /* RGB masks (10 bits each, left justified) */
- u32 shift; /* RGB MSB positions in the memory word */
- u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */
+ u32 format; /* DRM format code */
+ u32 rgb_code[3]; /* (width&7), MS bit position, 10-bit mask */
+ u32 bpp; /* Bytes per pixel minus one */
+};
+
+static const struct rp1dpi_ipixfmt my_formats[] = {
+ {
+ .format = DRM_FORMAT_XRGB8888,
+ .rgb_code = {
+ RGB_CODE(0, 23, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 7, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_XBGR8888,
+ .rgb_code = {
+ RGB_CODE(0, 7, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 23, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_ARGB8888,
+ .rgb_code = {
+ RGB_CODE(0, 23, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 7, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_ABGR8888,
+ .rgb_code = {
+ RGB_CODE(0, 7, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 23, 0x3fc),
+ },
+ .bpp = 3,
+ },
+ {
+ .format = DRM_FORMAT_RGB888,
+ .rgb_code = {
+ RGB_CODE(0, 23, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 7, 0x3fc),
+ },
+ .bpp = 2,
+ },
+ {
+ .format = DRM_FORMAT_BGR888,
+ .rgb_code = {
+ RGB_CODE(0, 7, 0x3fc),
+ RGB_CODE(0, 15, 0x3fc),
+ RGB_CODE(0, 23, 0x3fc),
+ },
+ .bpp = 2,
+ },
+ {
+ .format = DRM_FORMAT_RGB565,
+ .rgb_code = {
+ RGB_CODE(5, 15, 0x3e0),
+ RGB_CODE(6, 10, 0x3f0),
+ RGB_CODE(5, 4, 0x3e0),
+ },
+ .bpp = 1,
+ },
};
#define IMASK_RGB(r, g, b) (FIELD_PREP_CONST(DPI_DMA_IMASK_R_MASK, r) | \
@@ -244,63 +322,13 @@ struct rp1dpi_ipixfmt {
FIELD_PREP_CONST(DPI_DMA_SHIFT_OG_MASK, g) | \
FIELD_PREP_CONST(DPI_DMA_SHIFT_OB_MASK, b))
-static const struct rp1dpi_ipixfmt my_formats[] = {
- {
- .format = DRM_FORMAT_XRGB8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(23, 15, 7),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_XBGR8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(7, 15, 23),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_ARGB8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(23, 15, 7),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_ABGR8888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(7, 15, 23),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 3),
- },
- {
- .format = DRM_FORMAT_RGB888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(23, 15, 7),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2),
- },
- {
- .format = DRM_FORMAT_BGR888,
- .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc),
- .shift = ISHIFT_RGB(7, 15, 23),
- .rgbsz = FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 2),
- },
- {
- .format = DRM_FORMAT_RGB565,
- .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
- .shift = ISHIFT_RGB(15, 10, 4),
- .rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)),
- },
- {
- .format = DRM_FORMAT_BGR565,
- .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0),
- .shift = ISHIFT_RGB(4, 10, 15),
- .rgbsz = (FIELD_PREP_CONST(DPI_DMA_RGBSZ_R_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_G_MASK, 6) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_B_MASK, 5) |
- FIELD_PREP_CONST(DPI_DMA_RGBSZ_BPP_MASK, 1)),
- }
-};
-
+/*
+ * Function to update *shift with output positions, and return output RGB masks.
+ * By the time we get here, RGB order has been normalized to RGB (R most significant).
+ * Note that an internal bus is 30 bits wide: bits [21:20], [11:10], [1:0] are dropped.
+ * This makes the packed RGB5656 and RGB666 formats problematic, as colour components
+ * need to straddle the gaps; we mitigate this by hijacking input masks and scaling.
+ */
static u32 set_output_format(u32 bus_format, u32 *shift, u32 *imask, u32 *rgbsz)
{
switch (bus_format) {
@@ -308,6 +336,7 @@ static u32 set_output_format(u32 bus_for
if (*shift == ISHIFT_RGB(15, 10, 4)) {
/* When framebuffer is RGB565, we can output RGB565 */
*shift = ISHIFT_RGB(15, 7, 0) | OSHIFT_RGB(19, 9, 0);
+ *imask = IMASK_RGB(0x3fc, 0x3fc, 0);
*rgbsz &= DPI_DMA_RGBSZ_BPP_MASK;
return OMASK_RGB(0x3fc, 0x3fc, 0);
}
@@ -322,7 +351,7 @@ static u32 set_output_format(u32 bus_for
case MEDIA_BUS_FMT_BGR666_1X18:
/* due to a HW limitation, bit-depth is effectively RGB444 */
*shift |= OSHIFT_RGB(23, 15, 7);
- *imask &= IMASK_RGB(0x3c0, 0x3c0, 0x3c0);
+ *imask = IMASK_RGB(0x3c0, 0x3c0, 0x3c0);
*rgbsz = BITS(DPI_DMA_RGBSZ_R, 2) | (*rgbsz & DPI_DMA_RGBSZ_BPP_MASK);
return OMASK_RGB(0x330, 0x3c0, 0x3c0);
@@ -359,7 +388,8 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi
struct drm_display_mode const *mode)
{
u32 shift, imask, omask, rgbsz, vctrl;
- int i;
+ u32 rgb_code[3];
+ int order, i;
drm_info(&dpi->drm,
"in_fmt=\'%c%c%c%c\' bus_fmt=0x%x mode=%dx%d total=%dx%d%s %dkHz %cH%cV%cD%cC",
@@ -373,26 +403,45 @@ void rp1dpi_hw_setup(struct rp1_dpi *dpi
de_inv ? '-' : '+',
dpi->clk_inv ? '-' : '+');
- /*
- * Configure all DPI/DMA block registers, except base address.
- * DMA will not actually start until a FB base address is specified
- * using rp1dpi_hw_update().
- */
+ /* Look up the input (in-memory) pixel format */
for (i = 0; i < ARRAY_SIZE(my_formats); ++i) {
if (my_formats[i].format == in_format)
break;
}
if (i >= ARRAY_SIZE(my_formats)) {
pr_err("%s: bad input format\n", __func__);
- i = 4;
+ i = ARRAY_SIZE(my_formats) - 1;
}
- if (BUS_FMT_IS_BGR(bus_format))
- i ^= 1;
- shift = my_formats[i].shift;
- imask = my_formats[i].mask;
- rgbsz = my_formats[i].rgbsz;
+
+ /*
+ * Although these RGB orderings refer to the output (DPI bus) format,
+ * here we permute the *input* components. After this point, "Red"
+ * will be most significant (highest numbered GPIOs), regardless
+ * of rgb_order or bus_format. This simplifies later workarounds.
+ */
+ order = dpi->rgb_order_override;
+ if (order == RP1DPI_ORDER_UNCHANGED)
+ order = BUS_FMT_IS_BGR(bus_format) ? RP1DPI_ORDER_BGR : RP1DPI_ORDER_RGB;
+ rgb_code[0] = my_formats[i].rgb_code[order & 3];
+ rgb_code[1] = my_formats[i].rgb_code[(order >> 8) & 3];
+ rgb_code[2] = my_formats[i].rgb_code[(order >> 16) & 3];
+ rgbsz = FIELD_PREP(DPI_DMA_RGBSZ_BPP_MASK, my_formats[i].bpp) |
+ FIELD_PREP(DPI_DMA_RGBSZ_R_MASK, RGB_SCALE(rgb_code[0])) |
+ FIELD_PREP(DPI_DMA_RGBSZ_G_MASK, RGB_SCALE(rgb_code[1])) |
+ FIELD_PREP(DPI_DMA_RGBSZ_B_MASK, RGB_SCALE(rgb_code[2]));
+ shift = FIELD_PREP(DPI_DMA_SHIFT_IR_MASK, RGB_SHIFT(rgb_code[0])) |
+ FIELD_PREP(DPI_DMA_SHIFT_IG_MASK, RGB_SHIFT(rgb_code[1])) |
+ FIELD_PREP(DPI_DMA_SHIFT_IB_MASK, RGB_SHIFT(rgb_code[2]));
+ imask = FIELD_PREP(DPI_DMA_IMASK_R_MASK, RGB_MASK(rgb_code[0])) |
+ FIELD_PREP(DPI_DMA_IMASK_G_MASK, RGB_MASK(rgb_code[1])) |
+ FIELD_PREP(DPI_DMA_IMASK_B_MASK, RGB_MASK(rgb_code[2]));
omask = set_output_format(bus_format, &shift, &imask, &rgbsz);
+ /*
+ * Configure all DPI/DMA block registers, except base address.
+ * DMA will not actually start until a FB base address is specified
+ * using rp1dpi_hw_update().
+ */
rp1dpi_hw_write(dpi, DPI_DMA_IMASK, imask);
rp1dpi_hw_write(dpi, DPI_DMA_OMASK, omask);
rp1dpi_hw_write(dpi, DPI_DMA_SHIFT, shift);

View File

@ -0,0 +1,102 @@
From 94de19285cc9bd781394bf1aa4fb8d401aac5195 Mon Sep 17 00:00:00 2001
From: James Sarrett <jsarrett@gmail.com>
Date: Sun, 26 Jan 2025 11:29:31 -0800
Subject: [PATCH] add ina238 to i2c-sensors
This patch adds the ina238 device tree parameters to the i2c-sensors
overlay. The ina238 driver needs 2 configuration parameters, shut_resistor
and ti,shunt-gain in addition to it's address, so they are added as well.
---
arch/arm/boot/dts/overlays/README | 13 ++++++++++
.../boot/dts/overlays/i2c-sensor-common.dtsi | 26 ++++++++++++++++++-
2 files changed, 38 insertions(+), 1 deletion(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -2486,11 +2486,20 @@ Params: addr Set the
ds1621 Select the Dallas Semiconductors DS1621 temp
sensor. Valid addresses 0x48-0x4f, default 0x48
+ gain Gain used for measuring shunt resistor current.
+ Valid values 1 or 4, default 1. (ina238 only,
+ disabled by default)
+
hdc100x Select the Texas Instruments HDC100x temp sensor
Valid addresses 0x40-0x43, default 0x40
htu21 Select the HTU21 temperature and humidity sensor
+ ina238 Select the TI INA238 power monitor. Valid
+ addresses 0x40-0x4F, default 0x40.
+ Uses parameters shunt-resistor and
+ ti,shunt-gain for configuration
+
int_pin Set the GPIO to use for interrupts (max30102,
mpu6050 and mpu9250 only)
@@ -2549,6 +2558,10 @@ Params: addr Set the
reset_pin GPIO to be used to reset the device (bno055
only, disabled by default)
+ shunt_resistor Value of shunt resistor used for current
+ measurement in uOhms. (ina238 only, disabled
+ by default)
+
sht3x Select the Sensirion SHT3x temperature and
humidity sensors. Valid addresses 0x44-0x45,
default 0x44
--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi
+++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi
@@ -526,6 +526,27 @@
};
};
+ fragment@35 {
+ target = <&i2cbus>;
+ __dormant__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ ina238: ina238@48 {
+ compatible = "ti,ina238";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x40>;
+ /* uOhms, uint32_t */
+ shunt-resistor = <1000>;
+ /* 1 or 4, (±40.96 mV or ±163.84 mV) */
+ ti,shunt-gain = <1>;
+ status = "okay";
+ };
+ };
+ };
+
fragment@99 {
target = <&gpio>;
__dormant__ {
@@ -573,6 +594,7 @@
bno055 = <0>,"+31";
sht4x = <0>,"+32";
adt7410 = <0>,"+34";
+ ina238 = <0>,"+35";
addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
<&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
@@ -582,7 +604,7 @@
<&ms5837>,"reg:0", <&ms8607>,"reg:0",
<&mpu6050>,"reg:0", <&mpu9250>,"reg:0",
<&bno055>,"reg:0", <&sht4x>,"reg:0",
- <&bmp380>,"reg:0", <&adt7410>,"reg:0";
+ <&bmp380>,"reg:0", <&adt7410>,"reg:0", <&ina238>,"reg:0";
int_pin = <&int_pins>, "brcm,pins:0",
<&int_pins>, "reg:0",
<&max30102>, "interrupts:0",
@@ -590,5 +612,7 @@
<&mpu9250>, "interrupts:0";
no_timeout = <&jc42>, "smbus-timeout-disable?";
reset_pin = <&bno055>,"reset-gpios:4", <0>,"+30";
+ shunt_resistor = <&ina238>,"shunt-resistor:0";
+ gain = <&ina238>,"ti,shunt-gain:0";
};
};

View File

@ -0,0 +1,57 @@
From aabe16b3cdc6172618803ed7a6002d1099d306e5 Mon Sep 17 00:00:00 2001
From: James Sarrett <jsarrett@gmail.com>
Date: Sun, 26 Jan 2025 22:07:02 -0800
Subject: [PATCH] add shtc3 to i2c-sensors
This patch adds the shtc3 device tree parameters to the i2c-sensors
overlay. The shtc3 driver needs no other configuration parameters, as the
i2c address is permanently baked in to the silicon.
---
arch/arm/boot/dts/overlays/README | 3 +++
.../arm/boot/dts/overlays/i2c-sensor-common.dtsi | 16 ++++++++++++++++
2 files changed, 19 insertions(+)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -2570,6 +2570,9 @@ Params: addr Set the
humidity sensors. Valid addresses 0x44-0x45,
default 0x44
+ shtc3 Select the Sensirion SHTC3 temperature and
+ humidity sensors.
+
si7020 Select the Silicon Labs Si7013/20/21 humidity/
temperature sensor
--- a/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi
+++ b/arch/arm/boot/dts/overlays/i2c-sensor-common.dtsi
@@ -547,6 +547,21 @@
};
};
+ fragment@36 {
+ target = <&i2cbus>;
+ __dormant__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ shtc3: shtc3@70 {
+ compatible = "sensirion,shtc3";
+ reg = <0x70>;
+ status = "okay";
+ };
+ };
+ };
+
fragment@99 {
target = <&gpio>;
__dormant__ {
@@ -595,6 +610,7 @@
sht4x = <0>,"+32";
adt7410 = <0>,"+34";
ina238 = <0>,"+35";
+ shtc3 = <0>,"+36";
addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
<&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",

View File

@ -0,0 +1,139 @@
From fa71765fd3c98fa170407e72e052004913da6874 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 27 Jan 2025 14:17:46 +0000
Subject: [PATCH] overlays: Regularisation and improvements
A few small improvements, with a view to making the updated overlays
behave the same before and after the big conversion.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm/boot/dts/overlays/ads1115-overlay.dts | 3 ++-
arch/arm/boot/dts/overlays/i2c-fan-overlay.dts | 4 ++--
arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 3 ++-
arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts | 3 ++-
arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 3 ++-
arch/arm/boot/dts/overlays/pca953x-overlay.dts | 2 --
arch/arm/boot/dts/overlays/pcf857x-overlay.dts | 2 +-
arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +-
arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts | 2 +-
9 files changed, 13 insertions(+), 11 deletions(-)
--- a/arch/arm/boot/dts/overlays/ads1115-overlay.dts
+++ b/arch/arm/boot/dts/overlays/ads1115-overlay.dts
@@ -120,7 +120,8 @@
chd_cfg = <&channel_d>,"reg:0";
chd_gain = <&channel_d>,"ti,gain:0";
chd_datarate = <&channel_d>,"ti,datarate:0";
- i2c0 = <&frag100>, "target:0=",<&i2c0>;
+ i2c0 = <&frag100>, "target:0=",<&i2c0>,
+ <0>,"+101+102";
i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>,
<0>,"+101+102";
i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>,
--- a/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c-fan-overlay.dts
@@ -17,7 +17,6 @@
emc2301: emc2301@2f {
compatible = "microchip,emc2301";
reg = <0x2f>;
- status = "okay";
#cooling-cells = <0x02>;
};
};
@@ -82,7 +81,8 @@
};
__overrides__ {
- i2c0 = <&frag100>,"target:0=",<&i2c0>;
+ i2c0 = <&frag100>,"target:0=",<&i2c0>,
+ <0>,"+101+102";
i2c_csi_dsi = <&frag100>,"target:0=",<&i2c_csi_dsi>,
<0>,"+101+102";
i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>,
--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
@@ -27,7 +27,8 @@
};
__overrides__ {
- i2c0 = <&frag100>, "target:0=",<&i2c0>;
+ i2c0 = <&frag100>, "target:0=",<&i2c0>,
+ <0>,"+101+102";
i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>,
<0>,"+101+102";
i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>,
--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
@@ -27,7 +27,8 @@
};
__overrides__ {
- i2c0 = <&frag100>, "target:0=",<&i2c0>;
+ i2c0 = <&frag100>, "target:0=",<&i2c0>,
+ <0>,"+101+102";
i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>,
<0>,"+101+102";
i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>,
--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
@@ -87,7 +87,8 @@
addr = <&mcp23017>,"reg:0", <&mcp23017_pins>,"reg:0";
mcp23008 = <0>,"=2";
noints = <0>,"!1!3";
- i2c0 = <&frag100>, "target:0=",<&i2c0>;
+ i2c0 = <&frag100>, "target:0=",<&i2c0>,
+ <0>,"+101+102";
i2c_csi_dsi = <&frag100>, "target:0=",<&i2c_csi_dsi>,
<0>,"+101+102";
i2c_csi_dsi0 = <&frag100>, "target:0=",<&i2c_csi_dsi0>,
--- a/arch/arm/boot/dts/overlays/pca953x-overlay.dts
+++ b/arch/arm/boot/dts/overlays/pca953x-overlay.dts
@@ -17,8 +17,6 @@
reg = <0x20>;
gpio-controller;
#gpio-cells = <2>;
-
- status = "okay";
};
};
};
--- a/arch/arm/boot/dts/overlays/pcf857x-overlay.dts
+++ b/arch/arm/boot/dts/overlays/pcf857x-overlay.dts
@@ -11,13 +11,13 @@
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
+ status = "okay";
pcf857x: pcf857x@0 {
compatible = "";
reg = <0x00>;
gpio-controller;
#gpio-cells = <2>;
- status = "okay";
};
};
};
--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
+++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts
@@ -27,7 +27,7 @@
};
fragment@1 {
- target-path = "/";
+ target = <&clocks>;
__overlay__ {
sc16is750_clk: sc16is750_i2c_clk@48 {
compatible = "fixed-clock";
--- a/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
+++ b/arch/arm/boot/dts/overlays/sc16is752-i2c-overlay.dts
@@ -27,7 +27,7 @@
};
fragment@1 {
- target-path = "/";
+ target = <&clocks>;
__overlay__ {
sc16is752_clk: sc16is752_i2c_clk@48 {
compatible = "fixed-clock";

View File

@ -0,0 +1,63 @@
From 8a08b4ad6dbd48a826b3052e52a4fdc88c3ac36e Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Thu, 30 Jan 2025 15:26:39 +0000
Subject: [PATCH] misc: rp1-pio: SM_CONFIG_XFER32 = larger DMA bufs
Add an ioctl type - SM_CONFIG_XFER32 - that takes uints for the buf_size
and buf_count values.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/misc/rp1-pio.c | 9 +++++++++
include/uapi/misc/rp1_pio_if.h | 8 ++++++++
2 files changed, 17 insertions(+)
--- a/drivers/misc/rp1-pio.c
+++ b/drivers/misc/rp1-pio.c
@@ -710,6 +710,14 @@ static int rp1_pio_sm_config_xfer_user(s
args->buf_size, args->buf_count);
}
+static int rp1_pio_sm_config_xfer32_user(struct rp1_pio_client *client, void *param)
+{
+ struct rp1_pio_sm_config_xfer32_args *args = param;
+
+ return rp1_pio_sm_config_xfer_internal(client, args->sm, args->dir,
+ args->buf_size, args->buf_count);
+}
+
static int rp1_pio_sm_tx_user(struct rp1_pio_device *pio, struct dma_info *dma,
const void __user *userbuf, size_t bytes)
{
@@ -970,6 +978,7 @@ struct handler_info {
HANDLER(SM_CONFIG_XFER, sm_config_xfer_user),
HANDLER(SM_XFER_DATA, sm_xfer_data_user),
HANDLER(SM_XFER_DATA32, sm_xfer_data32_user),
+ HANDLER(SM_CONFIG_XFER32, sm_config_xfer32_user),
HANDLER(CAN_ADD_PROGRAM, can_add_program),
HANDLER(ADD_PROGRAM, add_program),
--- a/include/uapi/misc/rp1_pio_if.h
+++ b/include/uapi/misc/rp1_pio_if.h
@@ -160,6 +160,13 @@ struct rp1_pio_sm_config_xfer_args {
uint16_t buf_count;
};
+struct rp1_pio_sm_config_xfer32_args {
+ uint16_t sm;
+ uint16_t dir;
+ uint32_t buf_size;
+ uint32_t buf_count;
+};
+
struct rp1_pio_sm_xfer_data_args {
uint16_t sm;
uint16_t dir;
@@ -185,6 +192,7 @@ struct rp1_access_hw_args {
#define PIO_IOC_SM_CONFIG_XFER _IOW(PIO_IOC_MAGIC, 0, struct rp1_pio_sm_config_xfer_args)
#define PIO_IOC_SM_XFER_DATA _IOW(PIO_IOC_MAGIC, 1, struct rp1_pio_sm_xfer_data_args)
#define PIO_IOC_SM_XFER_DATA32 _IOW(PIO_IOC_MAGIC, 2, struct rp1_pio_sm_xfer_data32_args)
+#define PIO_IOC_SM_CONFIG_XFER32 _IOW(PIO_IOC_MAGIC, 3, struct rp1_pio_sm_config_xfer32_args)
#define PIO_IOC_READ_HW _IOW(PIO_IOC_MAGIC, 8, struct rp1_access_hw_args)
#define PIO_IOC_WRITE_HW _IOW(PIO_IOC_MAGIC, 9, struct rp1_access_hw_args)

View File

@ -0,0 +1,29 @@
From 54a442deb925c37346abbbcc566234757925910c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 3 Feb 2025 17:50:20 +0000
Subject: [PATCH] spi: dw: Wait for idle after TX
If this is a DMA transfer, and if there is no simultaneous RX transfer,
wait for the interface to go idle before reporting that TX is done.
Link: https://forums.raspberrypi.com/viewtopic.php?t=383027
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-dma.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -304,6 +304,11 @@ static int dw_spi_dma_wait_tx_done(struc
return -EIO;
}
+ if (!xfer->rx_buf) {
+ while (dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY)
+ cpu_relax();
+ }
+
return 0;
}

View File

@ -0,0 +1,42 @@
From e0a21a407b78477aa530800255d53405950cb1fb Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 3 Feb 2025 14:44:08 +0000
Subject: [PATCH] misc: rp1-pio: Error out on incompatible firmware
If the RP1 firmware has reported an error then return that from the PIO
probe function, otherwise defer the probing.
Link: https://github.com/raspberrypi/linux/issues/6642
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/misc/rp1-pio.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
--- a/drivers/misc/rp1-pio.c
+++ b/drivers/misc/rp1-pio.c
@@ -1277,8 +1277,10 @@ static int rp1_pio_probe(struct platform
return dev_err_probe(dev, pdev->id, "alias is missing\n");
fw = devm_rp1_firmware_get(dev, dev->of_node);
- if (IS_ERR_OR_NULL(fw))
- return dev_err_probe(dev, -ENOENT, "failed to contact RP1 firmware\n");
+ if (!fw)
+ return dev_err_probe(dev, -EPROBE_DEFER, "failed to find RP1 firmware driver\n");
+ if (IS_ERR(fw))
+ return dev_err_probe(dev, PTR_ERR(fw), "failed to contact RP1 firmware\n");
ret = rp1_firmware_get_feature(fw, FOURCC_PIO, &op_base, &op_count);
if (ret < 0)
return ret;
@@ -1355,6 +1357,11 @@ static void rp1_pio_remove(struct platfo
if (g_pio == pio)
g_pio = NULL;
+
+ device_destroy(pio->dev_class, pio->dev_num);
+ cdev_del(&pio->cdev);
+ class_destroy(pio->dev_class);
+ unregister_chrdev_region(pio->dev_num, 1);
}
static const struct of_device_id rp1_pio_ids[] = {

View File

@ -0,0 +1,103 @@
From 3f60adc5ce8238996ec43d2b76a6e38e46f8271b Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Mon, 3 Feb 2025 14:51:52 +0000
Subject: [PATCH] firmware: rp1: Linger on firmware failure
To avoid pointless retries, let the probe function succeed if the
firmware interface is configured correctly but the firmware is
incompatible. The value of the private drvdata field holds the outcome.
Link: https://github.com/raspberrypi/linux/issues/6642
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/firmware/rp1.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
--- a/drivers/firmware/rp1.c
+++ b/drivers/firmware/rp1.c
@@ -114,7 +114,8 @@ static void rp1_firmware_delete(struct k
void rp1_firmware_put(struct rp1_firmware *fw)
{
- kref_put(&fw->consumers, rp1_firmware_delete);
+ if (!IS_ERR_OR_NULL(fw))
+ kref_put(&fw->consumers, rp1_firmware_delete);
}
EXPORT_SYMBOL_GPL(rp1_firmware_put);
@@ -157,7 +158,7 @@ struct rp1_firmware *rp1_firmware_get(st
const char *match = rp1_firmware_of_match[0].compatible;
struct platform_device *pdev;
struct device_node *fwnode;
- struct rp1_firmware *fw;
+ struct rp1_firmware *fw = NULL;
if (!client)
return NULL;
@@ -166,17 +167,17 @@ struct rp1_firmware *rp1_firmware_get(st
return NULL;
if (!of_device_is_compatible(fwnode, match)) {
of_node_put(fwnode);
- return NULL;
+ return ERR_PTR(-ENXIO);
}
pdev = of_find_device_by_node(fwnode);
of_node_put(fwnode);
if (!pdev)
- goto err_exit;
+ return ERR_PTR(-ENXIO);
fw = platform_get_drvdata(pdev);
- if (!fw)
+ if (IS_ERR_OR_NULL(fw))
goto err_exit;
if (!kref_get_unless_zero(&fw->consumers))
@@ -188,7 +189,7 @@ struct rp1_firmware *rp1_firmware_get(st
err_exit:
put_device(&pdev->dev);
- return NULL;
+ return fw;
}
EXPORT_SYMBOL_GPL(rp1_firmware_get);
@@ -204,8 +205,8 @@ struct rp1_firmware *devm_rp1_firmware_g
int ret;
fw = rp1_firmware_get(client);
- if (!fw)
- return NULL;
+ if (IS_ERR_OR_NULL(fw))
+ return fw;
ret = devm_add_action_or_reset(dev, devm_rp1_firmware_put, fw);
if (ret)
@@ -270,19 +271,18 @@ static int rp1_firmware_probe(struct pla
init_completion(&fw->c);
kref_init(&fw->consumers);
- platform_set_drvdata(pdev, fw);
-
ret = rp1_firmware_message(fw, GET_FIRMWARE_VERSION,
NULL, 0, &version, sizeof(version));
if (ret == sizeof(version)) {
dev_info(dev, "RP1 Firmware version %08x%08x%08x%08x%08x\n",
version[0], version[1], version[2], version[3], version[4]);
- ret = 0;
- } else if (ret >= 0) {
- ret = -EIO;
+ platform_set_drvdata(pdev, fw);
+ } else {
+ rp1_firmware_put(fw);
+ platform_set_drvdata(pdev, ERR_PTR(-ENOENT));
}
- return ret;
+ return 0;
}
static int rp1_firmware_remove(struct platform_device *pdev)

View File

@ -0,0 +1,30 @@
From 4d577c42b47dfffda80da995fafd5b16fdb242e2 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 4 Feb 2025 13:18:45 +0000
Subject: [PATCH] mailbox: rp1: Don't claim channels in of_xlate
The of_xlate method saves the calculated event mask in the con_priv
field. It also rejects subsequent attempt to use that channel because
the mask is non-zero, which causes a repeated instantiation of a client
driver to fail.
The of_xlate method is not meant to be a point of resource acquisition.
Leave the con_priv initialisation, but drop the test that it was
previously zero.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/mailbox/rp1-mailbox.c | 2 --
1 file changed, 2 deletions(-)
--- a/drivers/mailbox/rp1-mailbox.c
+++ b/drivers/mailbox/rp1-mailbox.c
@@ -133,8 +133,6 @@ static struct mbox_chan *rp1_mbox_xlate(
return ERR_PTR(-EINVAL);
chan = &mbox->chans[doorbell];
- if (chan->con_priv)
- return ERR_PTR(-EBUSY);
chan->con_priv = (void *)(uintptr_t)(1 << doorbell);

View File

@ -0,0 +1,25 @@
From fab0093d88452972f05f4b13e91e31d00b55421a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 4 Feb 2025 15:25:30 +0000
Subject: [PATCH] fixup! spi: dw: Wait for idle after TX
Relax a bit harder - transmission of the last bits may take a while.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/spi/spi-dw-dma.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -305,8 +305,9 @@ static int dw_spi_dma_wait_tx_done(struc
}
if (!xfer->rx_buf) {
+ delay.value = dws->n_bytes * BITS_PER_BYTE;
while (dw_readl(dws, DW_SPI_SR) & DW_SPI_SR_BUSY)
- cpu_relax();
+ spi_delay_exec(&delay, xfer);
}
return 0;

View File

@ -0,0 +1,76 @@
From 2cdd83392ba025cc88072c0153d443fc59919960 Mon Sep 17 00:00:00 2001
From: j-schambacher <joerg@hifiberry.com>
Date: Mon, 10 Feb 2025 14:58:34 +0100
Subject: [PATCH] dtoverlays: adds support for Hifiberry ADC8x to the DAC8x
Allows the usage of ADC8x stacked on top of the DAC8x.
Activates all I2S pins and uses now the dummy-dai instead
of the formerly used pcm5102 to allow the use of a
capture device, too. The simple card driver will
probe for the ADC8x and may activate the 8 channel
capture. Uses GPIO5 for detection.
Signed-off-by: j-schambacher <joerg@hifiberry.com>
---
arch/arm/boot/dts/overlays/README | 3 +++
.../boot/dts/overlays/hifiberry-dac8x-overlay.dts | 14 ++++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -1879,6 +1879,9 @@ Params: <None>
Name: hifiberry-dac8x
Info: Configures the HifiBerry DAC8X audio cards (only on Pi5)
+ This driver also detects a stacked ADC8x and activates the
+ capture capabilities.
+ Note: for standalone use of the ADC8x activate the ADC8x module.
Load: dtoverlay=hifiberry-dac8x
Params: <None>
--- a/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts
+++ b/arch/arm/boot/dts/overlays/hifiberry-dac8x-overlay.dts
@@ -1,7 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
// Definitions for HiFiBerry DAC8x
/dts-v1/;
/plugin/;
+#include <dt-bindings/gpio/gpio.h>
+
/ {
compatible = "brcm,bcm2712";
@@ -10,8 +13,10 @@
__overlay__ {
rp1_i2s0_dac8x: rp1_i2s0_dac8x {
function = "i2s0";
- pins = "gpio18", "gpio19", "gpio21",
- "gpio23", "gpio25", "gpio27";
+ pins = "gpio18", "gpio19", "gpio20",
+ "gpio21", "gpio22", "gpio23",
+ "gpio24", "gpio25", "gpio26",
+ "gpio27";
bias-disable;
status = "okay";
};
@@ -30,9 +35,9 @@
fragment@2 {
target-path = "/";
__overlay__ {
- pcm5102a-codec {
+ dummy-codec {
#sound-dai-cells = <0>;
- compatible = "ti,pcm5102a";
+ compatible = "snd-soc-dummy";
status = "okay";
};
};
@@ -43,6 +48,7 @@
__overlay__ {
compatible = "hifiberry,hifiberry-dac8x";
i2s-controller = <&i2s_clk_producer>;
+ hasadc-gpio = <&gpio 5 GPIO_ACTIVE_LOW>;
status = "okay";
};
};

View File

@ -0,0 +1,75 @@
From d664f45f77423b03e5a435e480822075c03331bd Mon Sep 17 00:00:00 2001
From: j-schambacher <joerg@hifiberry.com>
Date: Mon, 10 Feb 2025 15:08:48 +0100
Subject: [PATCH] ASoC: adds ADC8x support to the Hifiberry DAC8x
The driver probes for the ADC8x which can be stacked on top
of the DAC8x. It enables a symmetric 8 channel capture using
the dummy-dai.
Signed-off-by: j-schambacher <joerg@hifiberry.com>
---
sound/soc/bcm/rpi-simple-soundcard.c | 38 +++++++++++++++++++++++++---
1 file changed, 34 insertions(+), 4 deletions(-)
--- a/sound/soc/bcm/rpi-simple-soundcard.c
+++ b/sound/soc/bcm/rpi-simple-soundcard.c
@@ -354,16 +354,46 @@ static struct snd_rpi_simple_drvdata drv
.dai = snd_hifiberry_dac_dai,
};
+SND_SOC_DAILINK_DEFS(hifiberry_dac8x,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
static int hifiberry_dac8x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ struct gpio_desc *gpio_desc;
+ bool has_adc;
- /* override the defaults to reflect 4 x PCM5102A on the card
- * and limit the sample rate to 192ksps
- */
+ /* Configure the codec for 8 channel playback */
codec_dai->driver->playback.channels_max = 8;
codec_dai->driver->playback.rates = SNDRV_PCM_RATE_8000_192000;
+ /* Activate capture based on ADC8x detection */
+ gpio_desc = devm_gpiod_get(card->dev, "hasadc", GPIOD_IN);
+ if (IS_ERR(gpio_desc)) {
+ dev_err(card->dev, "Failed to get GPIO: %ld\n", PTR_ERR(gpio_desc));
+ return PTR_ERR(gpio_desc);
+ }
+
+ has_adc = gpiod_get_value(gpio_desc);
+
+ if (has_adc) {
+ struct snd_soc_dai_link *dai = rtd->dai_link;
+
+ dev_info(card->dev, "ADC8x detected: capture enabled\n");
+ codec_dai->driver->symmetric_rate = 1;
+ codec_dai->driver->symmetric_channels = 1;
+ codec_dai->driver->symmetric_sample_bits = 1;
+ codec_dai->driver->capture.rates = SNDRV_PCM_RATE_8000_192000;
+ dai->name = "HiFiBerry DAC8xADC8x";
+ dai->stream_name = "HiFiBerry DAC8xADC8x HiFi";
+ } else {
+ dev_info(card->dev, "no ADC8x detected\n");
+ rtd->dai_link->playback_only = 1; // Disable capture
+ }
+
return 0;
}
@@ -375,7 +405,7 @@ static struct snd_soc_dai_link snd_hifib
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.init = hifiberry_dac8x_init,
- SND_SOC_DAILINK_REG(hifiberry_dac),
+ SND_SOC_DAILINK_REG(hifiberry_dac8x),
},
};

View File

@ -1,50 +1,9 @@
From fa846f5991de6c37db1f40e26a39f52c130f2bc7 Mon Sep 17 00:00:00 2001
From: Jonathan Bell <jonathan@raspberrypi.com>
Date: Mon, 13 Sep 2021 11:14:32 +0100
Subject: [PATCH 0519/1085] usb: dwc3: Set DMA and coherent masks early
From 1b1e75ae7d69816609a95ff2fb92729a2ff04d8e Mon Sep 17 00:00:00 2001
From: Dom Cobley <popcornmix@gmail.com>
Date: Mon, 10 Feb 2025 13:26:33 +0000
Subject: [PATCH] Reapply "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>
This reverts commit 09dfdf6129532e19b2cfd4992d1d09e7119ccd48.
---
drivers/phy/broadcom/Kconfig | 2 +-
.../phy/broadcom/phy-brcm-usb-init-synopsys.c | 59 +++++++++++++++++++
@ -246,7 +205,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
ret = dwc3_phy_power_on(dwc);
if (ret)
goto err_exit_phy;
@@ -1377,6 +1397,24 @@ static int dwc3_core_init(struct dwc3 *d
@@ -1386,6 +1406,24 @@ static int dwc3_core_init(struct dwc3 *d
dwc3_config_threshold(dwc);
@ -271,7 +230,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
return 0;
err_power_off_phy:
@@ -1520,6 +1558,7 @@ static void dwc3_get_properties(struct d
@@ -1529,6 +1567,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;
@ -279,7 +238,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
/* default to highest possible threshold */
lpm_nyet_threshold = 0xf;
@@ -1540,6 +1579,9 @@ static void dwc3_get_properties(struct d
@@ -1549,6 +1588,9 @@ static void dwc3_get_properties(struct d
*/
tx_fifo_resize_max_num = 6;
@ -289,7 +248,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
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);
@@ -1654,6 +1696,9 @@ static void dwc3_get_properties(struct d
@@ -1669,6 +1711,9 @@ static void dwc3_get_properties(struct d
dwc->dis_split_quirk = device_property_read_bool(dev,
"snps,dis-split-quirk");
@ -299,7 +258,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
dwc->lpm_nyet_threshold = lpm_nyet_threshold;
dwc->tx_de_emphasis = tx_de_emphasis;
@@ -1671,6 +1716,8 @@ static void dwc3_get_properties(struct d
@@ -1686,6 +1731,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;
@ -308,7 +267,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
}
@@ -1963,6 +2010,12 @@ static int dwc3_probe(struct platform_de
@@ -1978,6 +2025,12 @@ static int dwc3_probe(struct platform_de
if (IS_ERR(dwc->usb_psy))
return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n");
@ -333,7 +292,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
/* Global Debug LSP MUX Select */
#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */
#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
@@ -1067,6 +1070,7 @@ struct dwc3_scratchpad_array {
@@ -1070,6 +1073,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
@ -341,7 +300,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
* @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
@@ -1304,6 +1308,7 @@ struct dwc3 {
@@ -1311,6 +1315,7 @@ struct dwc3 {
u8 tx_max_burst_prd;
u8 tx_fifo_resize_max_num;
u8 clear_stall_protocol;

View File

@ -0,0 +1,119 @@
From 081eebdeccfd12e0aaba4b64c9f87b608777913b Mon Sep 17 00:00:00 2001
From: Micke Prag <micke.prag@gmail.com>
Date: Thu, 13 Feb 2025 22:08:43 +0100
Subject: [PATCH] overlays: Add OpenHydroponics RootMaster overlay
Signed-off-by: Micke Prag <micke.prag@gmail.com>
---
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 7 ++
.../boot/dts/overlays/rootmaster-overlay.dts | 77 +++++++++++++++++++
3 files changed, 85 insertions(+)
create mode 100644 arch/arm/boot/dts/overlays/rootmaster-overlay.dts
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -228,6 +228,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
qca7000-uart0.dtbo \
ramoops.dtbo \
ramoops-pi4.dtbo \
+ rootmaster.dtbo \
rotary-encoder.dtbo \
rpi-backlight.dtbo \
rpi-codeczero.dtbo \
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -4084,6 +4084,13 @@ Params: base-addr Where to
console-size Size of non-panic dmesg captures (default 0)
+Name: rootmaster
+Info: Overlay for OpenHydroponics RootMaster board.
+ https://openhydroponics.com/hw/rootmaster
+Load: dtoverlay=rootmaster
+Params: <None>
+
+
Name: rotary-encoder
Info: Overlay for GPIO connected rotary encoder.
Load: dtoverlay=rotary-encoder,<param>=<val>
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/rootmaster-overlay.dts
@@ -0,0 +1,77 @@
+// redo: ovmerge -c mcp251xfd-overlay.dts,spi0-0,interrupt=25 w1-gpio-overlay.dts,gpiopin=4
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/bcm2835.h>
+
+/ {
+ compatible = "brcm,bcm2835";
+ fragment@0 {
+ target = <&spidev0>;
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+ mcp251xfd_pins: mcp251xfd_spi0_0_pins {
+ brcm,pins = <25>;
+ brcm,function = <BCM2835_FSEL_GPIO_IN>;
+ };
+ };
+ };
+ fragment@2 {
+ target-path = "/clocks";
+ __overlay__ {
+ clk_mcp251xfd_osc: mcp251xfd-spi0-0-osc {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <40000000>;
+ };
+ };
+ };
+ fragment@3 {
+ target = <&spi0>;
+ __overlay__ {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mcp251xfd@0 {
+ compatible = "microchip,mcp251xfd";
+ reg = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcp251xfd_pins>;
+ spi-max-frequency = <20000000>;
+ interrupt-parent = <&gpio>;
+ interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&clk_mcp251xfd_osc>;
+ };
+ };
+ };
+ fragment@4 {
+ target-path = "/";
+ __overlay__ {
+ onewire@4 {
+ compatible = "w1-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&w1_pins>;
+ gpios = <&gpio 4 0>;
+ status = "okay";
+ };
+ };
+ };
+ fragment@5 {
+ target = <&gpio>;
+ __overlay__ {
+ w1_pins: w1_pins@4 {
+ brcm,pins = <4>;
+ brcm,function = <0>;
+ brcm,pull = <0>;
+ };
+ };
+ };
+};

View File

@ -0,0 +1,37 @@
From 011cbf22d7583687ae18690185169e5da0be000a Mon Sep 17 00:00:00 2001
From: Yuriy Pasichnyk <yurijpasichnyk11@gmail.com>
Date: Tue, 18 Feb 2025 16:20:31 +0200
Subject: [PATCH] media: i2c: arducam-pivariety: Fix mutex init and NULL
pointer
The mutex used in arducam-pivariety was not properly initialized,
which could lead to undefined behavior. This also caused a NULL
pointer dereference under certain conditions.
This patch ensures the mutex is correctly initialized during probe
and prevents NULL pointer dereferences.
Signed-off-by: Yuriy Pasichnyk <yurijpasichnyk11@gmail.com>
---
drivers/media/i2c/arducam-pivariety.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/media/i2c/arducam-pivariety.c
+++ b/drivers/media/i2c/arducam-pivariety.c
@@ -1208,6 +1208,8 @@ static int pivariety_enum_controls(struc
if (ret)
return ret;
+ mutex_init(&pivariety->mutex);
+
index = 0;
while (1) {
ret = pivariety_write(pivariety, CTRL_INDEX_REG, index);
@@ -1295,6 +1297,7 @@ static int pivariety_enum_controls(struc
v4l2_ctrl_handler_setup(ctrl_hdlr);
return 0;
err:
+ mutex_destroy(&pivariety->mutex);
return -ENODEV;
}

View File

@ -0,0 +1,32 @@
From af9965a855a8c6c7140bbcccfa89eec7e90a993d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 25 Feb 2025 12:16:33 +0000
Subject: [PATCH] misc: rp1-pio: Demote fw probe error to warning
Support for the RP1 firmware mailbox API is rolling out to Pi 5 EEPROM
images. For most users, the fact that the PIO is not available is no
cause for alarm. Change the message to a warning, so that it does not
appear with "quiet" in cmdline.txt.
Link: https://github.com/raspberrypi/linux/issues/6642
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
drivers/misc/rp1-pio.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/misc/rp1-pio.c
+++ b/drivers/misc/rp1-pio.c
@@ -1279,8 +1279,10 @@ static int rp1_pio_probe(struct platform
fw = devm_rp1_firmware_get(dev, dev->of_node);
if (!fw)
return dev_err_probe(dev, -EPROBE_DEFER, "failed to find RP1 firmware driver\n");
- if (IS_ERR(fw))
- return dev_err_probe(dev, PTR_ERR(fw), "failed to contact RP1 firmware\n");
+ if (IS_ERR(fw)) {
+ dev_warn(dev, "failed to contact RP1 firmware\n");
+ return PTR_ERR(fw);
+ }
ret = rp1_firmware_get_feature(fw, FOURCC_PIO, &op_base, &op_count);
if (ret < 0)
return ret;

View File

@ -0,0 +1,38 @@
From a4e7897eef1ad4628572a6abfd30291209a0bf43 Mon Sep 17 00:00:00 2001
From: Richard Oliver <richard.oliver@raspberrypi.com>
Date: Tue, 25 Feb 2025 15:06:23 +0000
Subject: [PATCH] dts: Add hogs for RP1 GPIO 46/48 on CM5
On Pi5 5, GPIOs 46/48 are made available on the 'CAM/DISP 1' connector as
'CD1_IO0_MICCLK'/'CD1_IO1_MICDAT1'. These GPIOs are not connected on
CM5.
Add hogs for GPIO 46/48 on CM5 to prevent camera drivers from
inadvertently using them when connected to 'CAM/DISP 1'
Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
@@ -734,6 +734,18 @@ spi10_cs_pins: &spi10_cs_gpio1 {};
function = "vbus1";
pins = "gpio42", "gpio43";
};
+
+ micclk1_hog {
+ gpio-hog;
+ gpios = <46 GPIO_ACTIVE_HIGH>;
+ output-high;
+ };
+
+ micdat1_hog {
+ gpio-hog;
+ gpios = <48 GPIO_ACTIVE_HIGH>;
+ output-high;
+ };
};
/ {

View File

@ -0,0 +1,25 @@
From f8f3e202fb083906fbc98ef6ea445e424779c076 Mon Sep 17 00:00:00 2001
From: Richard Oliver <richard.oliver@raspberrypi.com>
Date: Tue, 25 Feb 2025 15:22:46 +0000
Subject: [PATCH] spi: rp2040-gpio-bridge: fix gpiod error handling
In some circumstances, devm_gpiod_get_array_optional() can return
PTR_ERR rather than NULL to indicate failure. Handle these cases.
Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
---
drivers/spi/spi-rp2040-gpio-bridge.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/spi/spi-rp2040-gpio-bridge.c
+++ b/drivers/spi/spi-rp2040-gpio-bridge.c
@@ -956,7 +956,8 @@ static void rp2040_gbdg_parse_dt(struct
rp2040_gbdg->fast_xfer_gpios =
devm_gpiod_get_array_optional(dev, "fast_xfer", GPIOD_ASIS);
- if (!rp2040_gbdg->fast_xfer_gpios) {
+ if (IS_ERR_OR_NULL(rp2040_gbdg->fast_xfer_gpios)) {
+ rp2040_gbdg->fast_xfer_gpios = NULL;
dev_info(dev, "Could not acquire fast_xfer-gpios\n");
goto node_put;
}

View File

@ -0,0 +1,37 @@
From 2e071057fded90e789c0101498e45a1778be93fe Mon Sep 17 00:00:00 2001
From: Richard Oliver <richard.oliver@raspberrypi.com>
Date: Tue, 25 Feb 2025 15:27:59 +0000
Subject: [PATCH] spi: rp2040-gpio-bridge: probe: Cfg fast_xfer clk
Fast transfer mode requires that the first bit of data is clocked with a
rising edge. This can cause extra bits of data to be clocked on hardware
where the clock signal uses a pull-up. This change ensures that clk is
driven low before fast data transfer mode is entered.
Signed-off-by: Richard Oliver <richard.oliver@raspberrypi.com>
---
drivers/spi/spi-rp2040-gpio-bridge.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/spi/spi-rp2040-gpio-bridge.c
+++ b/drivers/spi/spi-rp2040-gpio-bridge.c
@@ -617,7 +617,6 @@ static int rp2040_gbdg_fast_xfer(struct
&clock_mux);
gpiod_direction_output(priv_data->fast_xfer_gpios->desc[0], 1);
- gpiod_direction_output(priv_data->fast_xfer_gpios->desc[1], 0);
rp2040_gbdg_rp1_calc_offsets(priv_data->fast_xfer_data_index,
&data_bank, &data_offset);
@@ -989,6 +988,11 @@ static void rp2040_gbdg_parse_dt(struct
goto node_put;
}
+ /*
+ * fast_xfer mode requires first data bit to be clocked on a rising
+ * edge. Configure as output-low here before fast_xfer mode is entered.
+ */
+ gpiod_direction_output(rp2040_gbdg->fast_xfer_gpios->desc[1], 0);
node_put:
if (of_args[0].np)
of_node_put(of_args[0].np);

View File

@ -0,0 +1,30 @@
From 1337c39626c14ca5e61b4cddbc097d87212a0b13 Mon Sep 17 00:00:00 2001
From: KubaTaba1uga <luna7337anul@proton.me>
Date: Mon, 3 Mar 2025 17:25:29 +0100
Subject: [PATCH] fix clang compilation error
---
drivers/dma-buf/heaps/system_heap.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
--- a/drivers/dma-buf/heaps/system_heap.c
+++ b/drivers/dma-buf/heaps/system_heap.c
@@ -50,11 +50,16 @@ static gfp_t order_flags[] = {HIGH_ORDER
* to match with the sizes often found in IOMMUs. Using order 4 pages instead
* of order 0 pages can significantly improve the performance of many IOMMUs
* by reducing TLB pressure and time spent updating page tables.
+ *
+ * Note: `module_max_order` must be set explicitly instead of using
+ * `orders[0]` to avoid Clang's "initializer element is not a
+ * compile-time constant" error.
*/
-static const unsigned int orders[] = {8, 4, 0};
+#define MAX_ORDERS_VALUE 8
+static const unsigned int orders[] = {MAX_ORDERS_VALUE, 4, 0};
#define NUM_ORDERS ARRAY_SIZE(orders)
-static unsigned int module_max_order = orders[0];
+static unsigned int module_max_order = MAX_ORDERS_VALUE;
module_param_named(max_order, module_max_order, uint, 0400);
MODULE_PARM_DESC(max_order, "Maximum allocation order override.");

View File

@ -0,0 +1,22 @@
From f1076a9d7a269d72b6707283560d0d38203cb07a Mon Sep 17 00:00:00 2001
From: KubaTaba1uga <luna7337anul@proton.me>
Date: Tue, 4 Mar 2025 09:50:30 +0100
Subject: [PATCH] delete the comment
---
drivers/dma-buf/heaps/system_heap.c | 4 ----
1 file changed, 4 deletions(-)
--- a/drivers/dma-buf/heaps/system_heap.c
+++ b/drivers/dma-buf/heaps/system_heap.c
@@ -50,10 +50,6 @@ static gfp_t order_flags[] = {HIGH_ORDER
* to match with the sizes often found in IOMMUs. Using order 4 pages instead
* of order 0 pages can significantly improve the performance of many IOMMUs
* by reducing TLB pressure and time spent updating page tables.
- *
- * Note: `module_max_order` must be set explicitly instead of using
- * `orders[0]` to avoid Clang's "initializer element is not a
- * compile-time constant" error.
*/
#define MAX_ORDERS_VALUE 8
static const unsigned int orders[] = {MAX_ORDERS_VALUE, 4, 0};

View File

@ -0,0 +1,66 @@
From ac56a225e0889e60e912ecd3a51333a5aee901fc Mon Sep 17 00:00:00 2001
From: Dave Stevenson <dave.stevenson@raspberrypi.com>
Date: Tue, 4 Mar 2025 15:28:53 +0000
Subject: [PATCH] dtoverlays: ov9281: Add continuous clock option as an
override
The previous change to make ov9281 always run in continuous clock
mode causes problems on Pi3 for reasons that aren't fully
understood. Pi4 is quite happy with it.
Change the default back to being non-continuous clock, and add
an override to select continuous clock mode and its slightly
greater max frame rate.
https://forums.raspberrypi.com/viewtopic.php?p=2300215
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
---
arch/arm/boot/dts/overlays/README | 3 +++
arch/arm/boot/dts/overlays/ov9281-overlay.dts | 16 +++++++++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -3570,6 +3570,9 @@ Params: rotation Mounting
Compute Module (CSI0, i2c_vc, and cam0_reg).
arducam Slow down the regulator for slow Arducam
modules.
+ clk-continuous Switch to continuous mode on the CSI clock lane,
+ which increases the maximum frame rate slightly.
+ Appears not to work on Pi3.
Name: papirus
--- a/arch/arm/boot/dts/overlays/ov9281-overlay.dts
+++ b/arch/arm/boot/dts/overlays/ov9281-overlay.dts
@@ -64,6 +64,20 @@
};
};
+ fragment@6 {
+ target = <&csi_ep>;
+ __overlay__ {
+ clock-noncontinuous;
+ };
+ };
+
+ fragment@7 {
+ target = <&cam_endpoint>;
+ __overlay__ {
+ clock-noncontinuous;
+ };
+ };
+
__overrides__ {
rotation = <&cam_node>,"rotation:0";
orientation = <&cam_node>,"orientation:0";
@@ -75,7 +89,7 @@
<&cam_node>, "avdd-supply:0=",<&cam0_reg>,
<&reg_frag>, "target:0=",<&cam0_reg>;
arducam = <0>, "+5";
-
+ clk-continuous = <0>, "-6-7";
};
};

View File

@ -0,0 +1,129 @@
From 32c319ba2f2fd662a3b7bd042515cd650807dbff Mon Sep 17 00:00:00 2001
From: Stefan Wahren <wahrenst@gmx.net>
Date: Sat, 1 Feb 2025 13:50:46 +0100
Subject: [PATCH] drm/v3d: Add clock handling
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
[ Upstream commit 4dd40b5f9c3d89b67af0dbe059cf4a51aac6bf06 ]
Since the initial commit 57692c94dcbe ("drm/v3d: Introduce a new DRM driver
for Broadcom V3D V3.x+") the struct v3d_dev reserved a pointer for
an optional V3D clock. But there wasn't any code, which fetched it.
So add the missing clock handling before accessing any V3D registers.
Signed-off-by: Stefan Wahren <wahrenst@gmx.net>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maíra Canal <mcanal@igalia.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250201125046.33030-1-wahrenst@gmx.net
[ Maíra: Backported to the downstream repository ]
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
drivers/gpu/drm/v3d/v3d_drv.c | 44 ++++++++++++++++++++++-------------
1 file changed, 28 insertions(+), 16 deletions(-)
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -232,11 +232,21 @@ static int v3d_platform_drm_probe(struct
if (ret)
return ret;
+ v3d->clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(v3d->clk))
+ return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n");
+
+ ret = clk_prepare_enable(v3d->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Couldn't enable the V3D clock\n");
+ return ret;
+ }
+
mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
ret = dma_set_mask_and_coherent(dev, mask);
if (ret)
- return ret;
+ goto clk_disable;
v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH);
@@ -251,32 +261,29 @@ static int v3d_platform_drm_probe(struct
ret = PTR_ERR(v3d->reset);
if (ret == -EPROBE_DEFER)
- return ret;
+ goto clk_disable;
v3d->reset = NULL;
ret = map_regs(v3d, &v3d->bridge_regs, "bridge");
if (ret) {
dev_err(dev,
"Failed to get reset control or bridge regs\n");
- return ret;
+ goto clk_disable;
}
}
- v3d->clk = devm_clk_get(dev, NULL);
- if (IS_ERR_OR_NULL(v3d->clk)) {
- if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
- dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
- return PTR_ERR(v3d->clk);
- }
-
node = rpi_firmware_find_node();
- if (!node)
- return -EINVAL;
+ if (!node) {
+ ret = -EINVAL;
+ goto clk_disable;
+ }
firmware = rpi_firmware_get(node);
of_node_put(node);
- if (!firmware)
- return -EPROBE_DEFER;
+ if (!firmware) {
+ ret = -EPROBE_DEFER;
+ goto clk_disable;
+ }
v3d->clk_up_rate = rpi_firmware_clk_get_max_rate(firmware,
RPI_FIRMWARE_V3D_CLK_ID);
@@ -293,14 +300,15 @@ static int v3d_platform_drm_probe(struct
if (v3d->ver < 41) {
ret = map_regs(v3d, &v3d->gca_regs, "gca");
if (ret)
- return ret;
+ goto clk_disable;
}
v3d->mmu_scratch = dma_alloc_wc(dev, 4096, &v3d->mmu_scratch_paddr,
GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
if (!v3d->mmu_scratch) {
dev_err(dev, "Failed to allocate MMU scratch page\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto clk_disable;
}
ret = v3d_gem_init(drm);
@@ -326,6 +334,8 @@ gem_destroy:
v3d_gem_destroy(drm);
dma_free:
dma_free_wc(dev, 4096, v3d->mmu_scratch, v3d->mmu_scratch_paddr);
+clk_disable:
+ clk_disable_unprepare(v3d->clk);
return ret;
}
@@ -340,6 +350,8 @@ static void v3d_platform_drm_remove(stru
dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch,
v3d->mmu_scratch_paddr);
+
+ clk_disable_unprepare(v3d->clk);
}
static struct platform_driver v3d_platform_driver = {

View File

@ -0,0 +1,61 @@
From 5258ca4ad089548a72657522443b9c3e46fd125b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
Date: Sat, 22 Feb 2025 14:40:21 -0300
Subject: [PATCH] drm/v3d: Don't run jobs that have errors flagged in its fence
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The V3D driver still relies on `drm_sched_increase_karma()` and
`drm_sched_resubmit_jobs()` for resubmissions when a timeout occurs.
The function `drm_sched_increase_karma()` marks the job as guilty, while
`drm_sched_resubmit_jobs()` sets an error (-ECANCELED) in the DMA fence of
that guilty job.
Because of this, we must check whether the jobs DMA fence has been
flagged with an error before executing the job. Otherwise, the same guilty
job may be resubmitted indefinitely, causing repeated GPU resets.
This patch adds a check for an error on the job's fence to prevent running
a guilty job that was previously flagged when the GPU timed out.
Note that the CPU and CACHE_CLEAN queues do not require this check, as
their jobs are executed synchronously once the DRM scheduler starts them.
Cc: stable@vger.kernel.org
Fixes: d223f98f0209 ("drm/v3d: Add support for compute shader dispatch.")
Fixes: 1584f16ca96e ("drm/v3d: Add support for submitting jobs to the TFU.")
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
drivers/gpu/drm/v3d/v3d_sched.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -292,11 +292,15 @@ v3d_tfu_job_run(struct drm_sched_job *sc
struct drm_device *dev = &v3d->drm;
struct dma_fence *fence;
+ if (unlikely(job->base.base.s_fence->finished.error))
+ return NULL;
+
+ v3d->tfu_job = job;
+
fence = v3d_fence_create(v3d, V3D_TFU);
if (IS_ERR(fence))
return NULL;
- v3d->tfu_job = job;
if (job->base.irq_fence)
dma_fence_put(job->base.irq_fence);
job->base.irq_fence = dma_fence_get(fence);
@@ -333,6 +337,9 @@ v3d_csd_job_run(struct drm_sched_job *sc
struct dma_fence *fence;
int i, csd_cfg0_reg, csd_cfg_reg_count;
+ if (unlikely(job->base.base.s_fence->finished.error))
+ return NULL;
+
v3d->csd_job = job;
v3d_invalidate_caches(v3d);

View File

@ -0,0 +1,84 @@
From 131564261399a36a5cf2ac2731ed1ceffba93d10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
Date: Sat, 22 Feb 2025 14:56:46 -0300
Subject: [PATCH] drm/v3d: Set job pointer to NULL when the job's fence has an
error
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Similar to commit e4b5ccd392b9 ("drm/v3d: Ensure job pointer is set to
NULL after job completion"), ensure the job pointer is set to `NULL` when
a job's fence has an error. Failing to do so can trigger kernel warnings
in specific scenarios, such as:
1. v3d_csd_job_run() assigns `v3d->csd_job = job`
2. CSD job exceeds hang limit, causing a timeout → v3d_gpu_reset_for_timeout()
3. GPU reset
4. drm_sched_resubmit_jobs() sets the job's fence to `-ECANCELED`.
5. v3d_csd_job_run() detects the fence error and returns NULL, not
submitting the job to the GPU
6. User-space runs `modprobe -r v3d`
7. v3d_gem_destroy()
v3d_gem_destroy() triggers a warning indicating that the CSD job never
ended, as we didn't set `v3d->csd_job` to NULL after the timeout. The same
can also happen to BIN, RENDER, and TFU jobs.
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
drivers/gpu/drm/v3d/v3d_sched.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -189,8 +189,12 @@ static struct dma_fence *v3d_bin_job_run
struct dma_fence *fence;
unsigned long irqflags;
- if (unlikely(job->base.base.s_fence->finished.error))
+ if (unlikely(job->base.base.s_fence->finished.error)) {
+ spin_lock_irqsave(&v3d->job_lock, irqflags);
+ v3d->bin_job = NULL;
+ spin_unlock_irqrestore(&v3d->job_lock, irqflags);
return NULL;
+ }
/* Lock required around bin_job update vs
* v3d_overflow_mem_work().
@@ -244,8 +248,10 @@ static struct dma_fence *v3d_render_job_
struct drm_device *dev = &v3d->drm;
struct dma_fence *fence;
- if (unlikely(job->base.base.s_fence->finished.error))
+ if (unlikely(job->base.base.s_fence->finished.error)) {
+ v3d->render_job = NULL;
return NULL;
+ }
v3d->render_job = job;
@@ -292,8 +298,10 @@ v3d_tfu_job_run(struct drm_sched_job *sc
struct drm_device *dev = &v3d->drm;
struct dma_fence *fence;
- if (unlikely(job->base.base.s_fence->finished.error))
+ if (unlikely(job->base.base.s_fence->finished.error)) {
+ v3d->tfu_job = NULL;
return NULL;
+ }
v3d->tfu_job = job;
@@ -337,8 +345,10 @@ v3d_csd_job_run(struct drm_sched_job *sc
struct dma_fence *fence;
int i, csd_cfg0_reg, csd_cfg_reg_count;
- if (unlikely(job->base.base.s_fence->finished.error))
+ if (unlikely(job->base.base.s_fence->finished.error)) {
+ v3d->csd_job = NULL;
return NULL;
+ }
v3d->csd_job = job;

View File

@ -0,0 +1,447 @@
From 97988373018e7fa7ff33b7774f88d30e48f71509 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
Date: Tue, 25 Feb 2025 20:44:59 -0300
Subject: [PATCH] drm/v3d: Associate a V3D tech revision to all supported
devices
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The V3D driver currently determines the GPU tech version (33, 41...)
by reading a register. This approach has worked so far since this
information wasnt needed before powering on the GPU.
V3D 7.1 introduces new registers that must be written to power on the
GPU, requiring us to know the V3D version beforehand. To address this,
associate each supported SoC with the corresponding VideoCore GPU version
as part of the device data.
To prevent possible mistakes, add an assertion to verify that the version
specified in the device data matches the one reported by the hardware.
If there is a mismatch, the kernel will trigger a warning.
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
drivers/gpu/drm/v3d/v3d_debugfs.c | 128 +++++++++++++++---------------
drivers/gpu/drm/v3d/v3d_drv.c | 22 +++--
drivers/gpu/drm/v3d/v3d_drv.h | 11 ++-
drivers/gpu/drm/v3d/v3d_gem.c | 12 +--
drivers/gpu/drm/v3d/v3d_irq.c | 10 +--
drivers/gpu/drm/v3d/v3d_sched.c | 12 +--
6 files changed, 106 insertions(+), 89 deletions(-)
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
@@ -22,74 +22,74 @@ struct v3d_reg_def {
};
static const struct v3d_reg_def v3d_hub_reg_defs[] = {
- 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),
+ REGDEF(V3D_GEN_33, V3D_GEN_42, V3D_HUB_AXICFG),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_UIFCFG),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT0),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT1),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT2),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_IDENT3),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_INT_STS),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_HUB_INT_MSK_STS),
+
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_CTL),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_VIO_ADDR),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_VIO_ID),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_MMU_DEBUG_INFO),
+
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_GMP_STATUS),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_GMP_CFG),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_GMP_VIO_ADDR),
};
static const struct v3d_reg_def v3d_gca_reg_defs[] = {
- REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN),
- REGDEF(33, 33, V3D_GCA_SAFE_SHUTDOWN_ACK),
+ REGDEF(V3D_GEN_33, V3D_GEN_33, V3D_GCA_SAFE_SHUTDOWN),
+ REGDEF(V3D_GEN_33, V3D_GEN_33, V3D_GCA_SAFE_SHUTDOWN_ACK),
};
static const struct v3d_reg_def v3d_core_reg_defs[] = {
- 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),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_IDENT0),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_IDENT1),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_IDENT2),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_MISCCFG),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_INT_STS),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CTL_INT_MSK_STS),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT0CS),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT0CA),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT0EA),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT1CS),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT1CA),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_CLE_CT1EA),
+
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_PTB_BPCA),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_PTB_BPCS),
+
+ REGDEF(V3D_GEN_33, V3D_GEN_41, V3D_GMP_STATUS),
+ REGDEF(V3D_GEN_33, V3D_GEN_41, V3D_GMP_CFG),
+ REGDEF(V3D_GEN_33, V3D_GEN_41, V3D_GMP_VIO_ADDR),
+
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_FDBGO),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_FDBGB),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_FDBGS),
+ REGDEF(V3D_GEN_33, V3D_GEN_71, V3D_ERR_STAT),
};
static const struct v3d_reg_def v3d_csd_reg_defs[] = {
- 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),
+ REGDEF(V3D_GEN_41, V3D_GEN_71, V3D_CSD_STATUS),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG0),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG1),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG2),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG3),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG4),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG5),
+ REGDEF(V3D_GEN_41, V3D_GEN_41, V3D_CSD_CURRENT_CFG6),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG0),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG1),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG2),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG3),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG4),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG5),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG6),
+ REGDEF(V3D_GEN_71, V3D_GEN_71, V3D_V7_CSD_CURRENT_CFG7),
};
static int v3d_v3d_debugfs_regs(struct seq_file *m, void *unused)
@@ -165,7 +165,7 @@ 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));
- if (v3d->ver <= 42) {
+ if (v3d->ver <= V3D_GEN_42) {
seq_printf(m, "TSY: %s\n",
str_yes_no(ident1 & V3D_HUB_IDENT1_WITH_TSY));
}
@@ -197,11 +197,11 @@ 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));
- if (v3d->ver <= 42) {
+ if (v3d->ver <= V3D_GEN_42) {
seq_printf(m, " BCG int: %d\n",
(ident2 & V3D_IDENT2_BCG_INT) != 0);
}
- if (v3d->ver < 40) {
+ if (v3d->ver < V3D_GEN_41) {
seq_printf(m, " Override TMU: %d\n",
(misccfg & V3D_MISCCFG_OVRTMUOUT) != 0);
}
@@ -311,8 +311,8 @@ static int v3d_measure_clock(struct seq_
int core = 0;
int measure_ms = 1000;
- if (v3d->ver >= 40) {
- int cycle_count_reg = v3d->ver < 71 ?
+ if (v3d->ver >= V3D_GEN_41) {
+ int cycle_count_reg = v3d->ver < V3D_GEN_71 ?
V3D_PCTR_CYCLE_COUNT : V3D_V7_PCTR_CYCLE_COUNT;
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
V3D_SET_FIELD(cycle_count_reg,
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -17,6 +17,7 @@
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -88,7 +89,7 @@ static int v3d_get_param_ioctl(struct dr
args->value = 1;
return 0;
case DRM_V3D_PARAM_SUPPORTS_PERFMON:
- args->value = (v3d->ver >= 40);
+ args->value = (v3d->ver >= V3D_GEN_41);
return 0;
case DRM_V3D_PARAM_SUPPORTS_MULTISYNC_EXT:
args->value = 1;
@@ -189,10 +190,10 @@ 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" },
+ { .compatible = "brcm,2711-v3d", .data = (void *)V3D_GEN_42 },
+ { .compatible = "brcm,2712-v3d", .data = (void *)V3D_GEN_71 },
+ { .compatible = "brcm,7268-v3d", .data = (void *)V3D_GEN_33 },
+ { .compatible = "brcm,7278-v3d", .data = (void *)V3D_GEN_41 },
{},
};
MODULE_DEVICE_TABLE(of, v3d_of_match);
@@ -211,6 +212,7 @@ static int v3d_platform_drm_probe(struct
struct device_node *node;
struct drm_device *drm;
struct v3d_dev *v3d;
+ enum v3d_gen gen;
int ret;
u32 mmu_debug;
u32 ident1;
@@ -224,6 +226,9 @@ static int v3d_platform_drm_probe(struct
platform_set_drvdata(pdev, drm);
+ gen = (enum v3d_gen)of_device_get_match_data(dev);
+ v3d->ver = gen;
+
ret = map_regs(v3d, &v3d->hub_regs, "hub");
if (ret)
return ret;
@@ -253,6 +258,11 @@ static int v3d_platform_drm_probe(struct
ident1 = V3D_READ(V3D_HUB_IDENT1);
v3d->ver = (V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_TVER) * 10 +
V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_REV));
+ /* Make sure that the V3D tech version retrieved from the HW is equal
+ * to the one advertised by the device tree.
+ */
+ WARN_ON(v3d->ver != gen);
+
v3d->cores = V3D_GET_FIELD(ident1, V3D_HUB_IDENT1_NCORES);
WARN_ON(v3d->cores > 1); /* multicore not yet implemented */
@@ -297,7 +307,7 @@ static int v3d_platform_drm_probe(struct
v3d->clk_down_rate =
(clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
- if (v3d->ver < 41) {
+ if (v3d->ver < V3D_GEN_41) {
ret = map_regs(v3d, &v3d->gca_regs, "gca");
if (ret)
goto clk_disable;
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -115,13 +115,20 @@ struct v3d_perfmon {
u64 values[];
};
+enum v3d_gen {
+ V3D_GEN_33 = 33,
+ V3D_GEN_41 = 41,
+ V3D_GEN_42 = 42,
+ V3D_GEN_71 = 71,
+};
+
struct v3d_dev {
struct drm_device drm;
/* Short representation (e.g. 33, 41) of the V3D tech version
* and revision.
*/
- int ver;
+ enum v3d_gen ver;
bool single_irq_line;
void __iomem *hub_regs;
@@ -213,7 +220,7 @@ to_v3d_dev(struct drm_device *dev)
static inline bool
v3d_has_csd(struct v3d_dev *v3d)
{
- return v3d->ver >= 41;
+ return v3d->ver >= V3D_GEN_41;
}
#define v3d_to_pdev(v3d) to_platform_device((v3d)->drm.dev)
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -69,7 +69,7 @@ v3d_init_core(struct v3d_dev *v3d, int c
* type. If you want the default behavior, you can still put
* "2" in the indirect texture state's output_type field.
*/
- if (v3d->ver < 40)
+ if (v3d->ver < V3D_GEN_41)
V3D_CORE_WRITE(core, V3D_CTL_MISCCFG, V3D_MISCCFG_OVRTMUOUT);
/* Whenever we flush the L2T cache, we always want to flush
@@ -89,7 +89,7 @@ v3d_init_hw_state(struct v3d_dev *v3d)
static void
v3d_idle_axi(struct v3d_dev *v3d, int core)
{
- if (v3d->ver >= 71)
+ if (v3d->ver >= V3D_GEN_71)
return;
V3D_CORE_WRITE(core, V3D_GMP_CFG, V3D_GMP_CFG_STOP_REQ);
@@ -105,7 +105,7 @@ v3d_idle_axi(struct v3d_dev *v3d, int co
static void
v3d_idle_gca(struct v3d_dev *v3d)
{
- if (v3d->ver >= 41)
+ if (v3d->ver >= V3D_GEN_41)
return;
V3D_GCA_WRITE(V3D_GCA_SAFE_SHUTDOWN, V3D_GCA_SAFE_SHUTDOWN_EN);
@@ -179,13 +179,13 @@ v3d_reset(struct v3d_dev *v3d)
static void
v3d_flush_l3(struct v3d_dev *v3d)
{
- if (v3d->ver < 41) {
+ if (v3d->ver < V3D_GEN_41) {
u32 gca_ctrl = V3D_GCA_READ(V3D_GCA_CACHE_CTRL);
V3D_GCA_WRITE(V3D_GCA_CACHE_CTRL,
gca_ctrl | V3D_GCA_CACHE_CTRL_FLUSH);
- if (v3d->ver < 33) {
+ if (v3d->ver < V3D_GEN_33) {
V3D_GCA_WRITE(V3D_GCA_CACHE_CTRL,
gca_ctrl & ~V3D_GCA_CACHE_CTRL_FLUSH);
}
@@ -198,7 +198,7 @@ v3d_flush_l3(struct v3d_dev *v3d)
static void
v3d_invalidate_l2c(struct v3d_dev *v3d, int core)
{
- if (v3d->ver > 32)
+ if (v3d->ver >= V3D_GEN_33)
return;
V3D_CORE_WRITE(core, V3D_CTL_L2CACTL,
--- a/drivers/gpu/drm/v3d/v3d_irq.c
+++ b/drivers/gpu/drm/v3d/v3d_irq.c
@@ -125,8 +125,8 @@ v3d_irq(int irq, void *arg)
status = IRQ_HANDLED;
}
- if ((v3d->ver < 71 && (intsts & V3D_INT_CSDDONE)) ||
- (v3d->ver >= 71 && (intsts & V3D_V7_INT_CSDDONE))) {
+ if ((v3d->ver < V3D_GEN_71 && (intsts & V3D_INT_CSDDONE)) ||
+ (v3d->ver >= V3D_GEN_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();
@@ -142,7 +142,7 @@ v3d_irq(int irq, void *arg)
/* We shouldn't be triggering these if we have GMP in
* always-allowed mode.
*/
- if (v3d->ver < 71 && (intsts & V3D_INT_GMPV))
+ if (v3d->ver < V3D_GEN_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 &
@@ -200,7 +200,7 @@ v3d_hub_irq(int irq, void *arg)
V3D_WRITE(V3D_MMU_CTL, V3D_READ(V3D_MMU_CTL));
- if (v3d->ver >= 41) {
+ if (v3d->ver >= V3D_GEN_41) {
axi_id = axi_id >> 5;
if (axi_id < ARRAY_SIZE(v3d41_axi_ids))
client = v3d41_axi_ids[axi_id];
@@ -219,7 +219,7 @@ v3d_hub_irq(int irq, void *arg)
status = IRQ_HANDLED;
}
- if (v3d->ver >= 71 && intsts & V3D_V7_HUB_INT_GMPV) {
+ if (v3d->ver >= V3D_GEN_71 && intsts & V3D_V7_HUB_INT_GMPV) {
dev_err(v3d->drm.dev, "GMP Violation\n");
status = IRQ_HANDLED;
}
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -288,7 +288,7 @@ static struct dma_fence *v3d_render_job_
return fence;
}
-#define V3D_TFU_REG(name) ((v3d->ver < 71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name)
+#define V3D_TFU_REG(name) ((v3d->ver < V3D_GEN_71) ? V3D_TFU_ ## name : V3D_V7_TFU_ ## name)
static struct dma_fence *
v3d_tfu_job_run(struct drm_sched_job *sched_job)
@@ -321,11 +321,11 @@ v3d_tfu_job_run(struct drm_sched_job *sc
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)
+ if (v3d->ver >= V3D_GEN_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)) {
+ if (v3d->ver >= V3D_GEN_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]);
@@ -367,8 +367,8 @@ 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);
- csd_cfg0_reg = v3d->ver < 71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0;
- csd_cfg_reg_count = v3d->ver < 71 ? 6 : 7;
+ csd_cfg0_reg = v3d->ver < V3D_GEN_71 ? V3D_CSD_QUEUED_CFG0 : V3D_V7_CSD_QUEUED_CFG0;
+ csd_cfg_reg_count = v3d->ver < V3D_GEN_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. */
@@ -475,7 +475,7 @@ 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->ver < 71 ? V3D_CSD_CURRENT_CFG4 :
+ u32 batches = V3D_CORE_READ(0, (v3d->ver < V3D_GEN_71 ? V3D_CSD_CURRENT_CFG4 :
V3D_V7_CSD_CURRENT_CFG4));
/* If we've made progress, skip reset and let the timer get

View File

@ -0,0 +1,43 @@
From 08e99bc475ad907f3087e4f14c2ddb6560514da1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
Date: Sat, 22 Feb 2025 15:26:39 -0300
Subject: [PATCH] dt-bindings: gpu: v3d: Add SMS to the registers' list
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
V3D 7.1 exposes a new register block, called V3D_SMS. As BCM2712 has a
V3D 7.1 core, add a new register item to the list. Similar to the GCA
and bridge register, SMS is optional and should only be added for V3D
7.1 variants.
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Nicolas Saenz Julienne <nsaenz@kernel.org>
Cc: devicetree@vger.kernel.org
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
+++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
@@ -27,14 +27,16 @@ properties:
- description: core0 register (required)
- description: GCA cache controller register (if GCA controller present)
- description: bridge register (if no external reset controller)
+ - description: SMS register (if SMS controller present)
minItems: 2
reg-names:
items:
- const: hub
- const: core0
- - enum: [ bridge, gca ]
- - enum: [ bridge, gca ]
+ - enum: [ bridge, gca, sms ]
+ - enum: [ bridge, gca, sms ]
+ - enum: [ bridge, gca, sms ]
minItems: 2
interrupts:

View File

@ -0,0 +1,198 @@
From 85e1a7592aa192d760159f9bc6e83d56fdf433f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
Date: Sat, 22 Feb 2025 15:49:49 -0300
Subject: [PATCH] drm/v3d: Use V3D_SMS registers for power on/off and reset on
V3D 7.x
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In addition to the standard reset controller, V3D 7.x requires configuring
the V3D_SMS registers for proper power on/off and reset. Add the new
registers to `v3d_regs.h` and ensure they are properly configured during
device probing, removal, and reset.
This change fixes GPU reset issues on the Raspberry Pi 5 (BCM2712).
Without exposing these registers, a GPU reset causes the GPU to hang,
stopping any further job execution and freezing the desktop GUI. The same
issue occurs when unloading and loading the v3d driver.
Link: https://github.com/raspberrypi/linux/issues/6660
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
drivers/gpu/drm/v3d/v3d_drv.c | 40 ++++++++++++++++++++++++++++++++++
drivers/gpu/drm/v3d/v3d_drv.h | 11 ++++++++++
drivers/gpu/drm/v3d/v3d_gem.c | 17 +++++++++++++++
drivers/gpu/drm/v3d/v3d_regs.h | 26 ++++++++++++++++++++++
4 files changed, 94 insertions(+)
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -198,6 +198,36 @@ static const struct of_device_id v3d_of_
};
MODULE_DEVICE_TABLE(of, v3d_of_match);
+static void
+v3d_idle_sms(struct v3d_dev *v3d)
+{
+ if (v3d->ver < V3D_GEN_71)
+ return;
+
+ V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_CLEAR_POWER_OFF);
+
+ if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS),
+ V3D_SMS_STATE) == V3D_SMS_IDLE), 100)) {
+ DRM_ERROR("Failed to power up SMS\n");
+ }
+
+ v3d_reset_sms(v3d);
+}
+
+static void
+v3d_power_off_sms(struct v3d_dev *v3d)
+{
+ if (v3d->ver < V3D_GEN_71)
+ return;
+
+ V3D_SMS_WRITE(V3D_SMS_TEE_CS, V3D_SMS_POWER_OFF);
+
+ if (wait_for((V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_TEE_CS),
+ V3D_SMS_STATE) == V3D_SMS_POWER_OFF_STATE), 100)) {
+ DRM_ERROR("Failed to power off SMS\n");
+ }
+}
+
static int
map_regs(struct v3d_dev *v3d, void __iomem **regs, const char *name)
{
@@ -237,6 +267,12 @@ static int v3d_platform_drm_probe(struct
if (ret)
return ret;
+ if (v3d->ver >= V3D_GEN_71) {
+ ret = map_regs(v3d, &v3d->sms_regs, "sms");
+ if (ret)
+ return ret;
+ }
+
v3d->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(v3d->clk))
return dev_err_probe(dev, PTR_ERR(v3d->clk), "Failed to get V3D clock\n");
@@ -247,6 +283,8 @@ static int v3d_platform_drm_probe(struct
return ret;
}
+ v3d_idle_sms(v3d);
+
mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO);
mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH));
ret = dma_set_mask_and_coherent(dev, mask);
@@ -361,6 +399,8 @@ static void v3d_platform_drm_remove(stru
dma_free_wc(v3d->drm.dev, 4096, v3d->mmu_scratch,
v3d->mmu_scratch_paddr);
+ v3d_power_off_sms(v3d);
+
clk_disable_unprepare(v3d->clk);
}
--- a/drivers/gpu/drm/v3d/v3d_drv.h
+++ b/drivers/gpu/drm/v3d/v3d_drv.h
@@ -135,6 +135,7 @@ struct v3d_dev {
void __iomem *core_regs[3];
void __iomem *bridge_regs;
void __iomem *gca_regs;
+ void __iomem *sms_regs;
struct clk *clk;
struct delayed_work clk_down_work;
unsigned long clk_up_rate, clk_down_rate;
@@ -277,6 +278,15 @@ to_v3d_fence(struct dma_fence *fence)
#define V3D_GCA_READ(offset) readl(v3d->gca_regs + offset)
#define V3D_GCA_WRITE(offset, val) writel(val, v3d->gca_regs + offset)
+#define V3D_SMS_IDLE 0x0
+#define V3D_SMS_ISOLATING_FOR_RESET 0xa
+#define V3D_SMS_RESETTING 0xb
+#define V3D_SMS_ISOLATING_FOR_POWER_OFF 0xc
+#define V3D_SMS_POWER_OFF_STATE 0xd
+
+#define V3D_SMS_READ(offset) readl(v3d->sms_regs + (offset))
+#define V3D_SMS_WRITE(offset, val) writel(val, v3d->sms_regs + (offset))
+
#define V3D_CORE_READ(core, offset) readl(v3d->core_regs[core] + offset)
#define V3D_CORE_WRITE(core, offset, val) writel(val, v3d->core_regs[core] + offset)
@@ -455,6 +465,7 @@ int v3d_wait_bo_ioctl(struct drm_device
struct drm_file *file_priv);
void v3d_job_cleanup(struct v3d_job *job);
void v3d_job_put(struct v3d_job *job);
+void v3d_reset_sms(struct v3d_dev *v3d);
void v3d_reset(struct v3d_dev *v3d);
void v3d_invalidate_caches(struct v3d_dev *v3d);
void v3d_clean_caches(struct v3d_dev *v3d);
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -152,6 +152,22 @@ v3d_reset_v3d(struct v3d_dev *v3d)
}
void
+v3d_reset_sms(struct v3d_dev *v3d)
+{
+ if (v3d->ver < V3D_GEN_71)
+ return;
+
+ V3D_SMS_WRITE(V3D_SMS_REE_CS, V3D_SET_FIELD(0x4, V3D_SMS_STATE));
+
+ if (wait_for(!(V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_REE_CS),
+ V3D_SMS_STATE) == V3D_SMS_ISOLATING_FOR_RESET) &&
+ !(V3D_GET_FIELD(V3D_SMS_READ(V3D_SMS_REE_CS),
+ V3D_SMS_STATE) == V3D_SMS_RESETTING), 100)) {
+ DRM_ERROR("Failed to wait for SMS reset\n");
+ }
+}
+
+void
v3d_reset(struct v3d_dev *v3d)
{
struct drm_device *dev = &v3d->drm;
@@ -166,6 +182,7 @@ v3d_reset(struct v3d_dev *v3d)
v3d_idle_axi(v3d, 0);
v3d_idle_gca(v3d);
+ v3d_reset_sms(v3d);
v3d_reset_v3d(v3d);
v3d_mmu_set_page_table(v3d);
--- a/drivers/gpu/drm/v3d/v3d_regs.h
+++ b/drivers/gpu/drm/v3d/v3d_regs.h
@@ -543,4 +543,30 @@
# define V3D_ERR_VPAERGS BIT(1)
# define V3D_ERR_VPAEABB BIT(0)
+#define V3D_SMS_REE_CS 0x00000
+#define V3D_SMS_TEE_CS 0x00400
+# define V3D_SMS_INTERRUPT BIT(31)
+# define V3D_SMS_POWER_OFF BIT(30)
+# define V3D_SMS_CLEAR_POWER_OFF BIT(29)
+# define V3D_SMS_LOCK BIT(28)
+# define V3D_SMS_CLEAR_LOCK BIT(27)
+# define V3D_SMS_SVP_MODE_EXIT BIT(26)
+# define V3D_SMS_CLEAR_SVP_MODE_EXIT BIT(25)
+# define V3D_SMS_SVP_MODE_ENTER BIT(24)
+# define V3D_SMS_CLEAR_SVP_MODE_ENTER BIT(23)
+# define V3D_SMS_THEIR_MODE_EXIT BIT(22)
+# define V3D_SMS_THEIR_MODE_ENTER BIT(21)
+# define V3D_SMS_OUR_MODE_EXIT BIT(20)
+# define V3D_SMS_CLEAR_OUR_MODE_EXIT BIT(19)
+# define V3D_SMS_SEQ_PC_MASK V3D_MASK(16, 10)
+# define V3D_SMS_SEQ_PC_SHIFT 10
+# define V3D_SMS_HUBCORE_STATUS_MASK V3D_MASK(9, 8)
+# define V3D_SMS_HUBCORE_STATUS_SHIFT 8
+# define V3D_SMS_NEW_MODE_MASK V3D_MASK(7, 6)
+# define V3D_SMS_NEW_MODE_SHIFT 6
+# define V3D_SMS_OLD_MODE_MASK V3D_MASK(5, 4)
+# define V3D_SMS_OLD_MODE_SHIFT 4
+# define V3D_SMS_STATE_MASK V3D_MASK(3, 0)
+# define V3D_SMS_STATE_SHIFT 0
+
#endif /* V3D_REGS_H */

View File

@ -0,0 +1,27 @@
From 3c21211667e35029054b0dfebdf292e4e7d5754b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ADra=20Canal?= <mcanal@igalia.com>
Date: Thu, 27 Feb 2025 21:00:42 -0300
Subject: [PATCH] dts: bcm2712: Add V3D_SMS register
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Maíra Canal <mcanal@igalia.com>
---
arch/arm64/boot/dts/broadcom/bcm2712.dtsi | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
+++ b/arch/arm64/boot/dts/broadcom/bcm2712.dtsi
@@ -1222,8 +1222,9 @@
v3d: v3d@2000000 {
compatible = "brcm,2712-v3d";
reg = <0x10 0x02000000 0x0 0x4000>,
- <0x10 0x02008000 0x0 0x6000>;
- reg-names = "hub", "core0";
+ <0x10 0x02008000 0x0 0x6000>,
+ <0x10 0x02030800 0x0 0x0700>;
+ reg-names = "hub", "core0", "sms";
power-domains = <&pm BCM2835_POWER_DOMAIN_GRAFX_V3D>;
resets = <&pm BCM2835_RESET_V3D>;

View File

@ -0,0 +1,21 @@
From 08d4e8f52256bd422d8a1f876411603f627d0a82 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Tue, 11 Mar 2025 08:58:52 +0000
Subject: [PATCH] dts: Remove the power key debounce on Pi 500
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-500.dts
@@ -7,7 +7,7 @@
};
&pwr_key {
- debounce-interval = <400>;
+ debounce-interval = <0>;
};
&gio {