aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux
diff options
context:
space:
mode:
authorÁlvaro Fernández Rojas <noltari@gmail.com>2020-03-23 08:48:08 +0100
committerÁlvaro Fernández Rojas <noltari@gmail.com>2020-03-23 08:48:08 +0100
commit6c9b5d6972aa84b85aa9d5d95b3e01f23525e929 (patch)
tree47f488bbfe8a0973955c34df627a30d81d7c8046 /target/linux
parent835d1c68a0f036c8b0d837a48b5a05fdfb2e8218 (diff)
downloadupstream-6c9b5d6972aa84b85aa9d5d95b3e01f23525e929.tar.gz
upstream-6c9b5d6972aa84b85aa9d5d95b3e01f23525e929.tar.bz2
upstream-6c9b5d6972aa84b85aa9d5d95b3e01f23525e929.zip
bcm27xx: sync 5.4 patches with RPi Foundation
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Diffstat (limited to 'target/linux')
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0119-Add-rpi-poe-fan-driver.patch4
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0475-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch45
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0476-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch1589
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0477-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch27
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0478-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch67
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0479-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch32
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch141
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch50
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch95
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Accept-extras-directly-after.patch77
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch76
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch49
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch64
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0487-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch247
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0488-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch157
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0489-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch38
-rw-r--r--target/linux/bcm27xx/patches-5.4/950-0490-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch41
17 files changed, 2797 insertions, 2 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0119-Add-rpi-poe-fan-driver.patch b/target/linux/bcm27xx/patches-5.4/950-0119-Add-rpi-poe-fan-driver.patch
index 574e547de9..8a1f57ad01 100644
--- a/target/linux/bcm27xx/patches-5.4/950-0119-Add-rpi-poe-fan-driver.patch
+++ b/target/linux/bcm27xx/patches-5.4/950-0119-Add-rpi-poe-fan-driver.patch
@@ -108,7 +108,7 @@ Signed-off-by: Serge Schneider <serge@raspberrypi.org>
+the fan to the user space through the hwmon sysfs interface.
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
-@@ -1346,6 +1346,17 @@ config SENSORS_RASPBERRYPI_HWMON
+@@ -1356,6 +1356,17 @@ config SENSORS_RASPBERRYPI_HWMON
This driver can also be built as a module. If so, the module
will be called raspberrypi-hwmon.
@@ -128,7 +128,7 @@ Signed-off-by: Serge Schneider <serge@raspberrypi.org>
depends on GPIOLIB || COMPILE_TEST
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
-@@ -144,6 +144,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591
+@@ -145,6 +145,7 @@ obj-$(CONFIG_SENSORS_PCF8591) += pcf8591
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/target/linux/bcm27xx/patches-5.4/950-0475-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch b/target/linux/bcm27xx/patches-5.4/950-0475-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch
new file mode 100644
index 0000000000..cdd14f7940
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0475-gpio-ir-overlay-add-parameter-to-configure-signal-po.patch
@@ -0,0 +1,45 @@
+From e253d03936265dc4ab8ae9ae89d2a885e80a45a6 Mon Sep 17 00:00:00 2001
+From: Matthias Reichl <hias@horus.com>
+Date: Fri, 6 Mar 2020 11:08:10 +0100
+Subject: [PATCH] gpio-ir-overlay: add parameter to configure signal
+ polarity (#3490)
+
+Standard IR receivers use inverted / active-low signalling
+and the gpio-ir overlay configures the GPIO appropriately
+as GPIO_ACTIVE_LOW (1).
+
+In order to support (rather rare) non-inverted / active-high
+signalling the GPIO needs to be configured as GPIO_ACTIVE_HIGH (0).
+
+Add an "invert" parameter to override this like in the gpio-ir-tx
+overlay.
+
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ arch/arm/boot/dts/overlays/README | 4 ++++
+ arch/arm/boot/dts/overlays/gpio-ir-overlay.dts | 1 +
+ 2 files changed, 5 insertions(+)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -754,6 +754,10 @@ Params: gpio_pin Input pi
+ gpio_pull Desired pull-up/down state (off, down, up)
+ Default is "up".
+
++ invert "1" = invert the input (active-low signalling).
++ "0" = non-inverted input (active-high
++ signalling). Default is "1".
++
+ rc-map-name Default rc keymap (can also be changed by
+ ir-keytable), defaults to "rc-rc6-mce"
+
+--- a/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
++++ b/arch/arm/boot/dts/overlays/gpio-ir-overlay.dts
+@@ -42,6 +42,7 @@
+ <&gpio_ir_pins>,"brcm,pins:0",
+ <&gpio_ir_pins>,"reg:0";
+ gpio_pull = <&gpio_ir_pins>,"brcm,pull:0"; // pull-up/down state
++ invert = <&gpio_ir>,"gpios:8"; // 0 = active high input
+
+ rc-map-name = <&gpio_ir>,"linux,rc-map-name"; // default rc map
+ };
diff --git a/target/linux/bcm27xx/patches-5.4/950-0476-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch b/target/linux/bcm27xx/patches-5.4/950-0476-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch
new file mode 100644
index 0000000000..8e66bccf6e
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0476-Add-support-for-merus-amp-soundcard-and-ma120x0p-cod.patch
@@ -0,0 +1,1589 @@
+From 76e0edf9676388c58bb5f0d7dda8eb8029926c6d Mon Sep 17 00:00:00 2001
+From: AMuszkat <ariel.muszkat@gmail.com>
+Date: Mon, 24 Feb 2020 22:56:59 +0100
+Subject: [PATCH] Add support for merus-amp soundcard and ma120x0p
+ codec
+
+correct checkpatch warnings and errors
+
+Signed-off-by: AMuszkat <ariel.muszkat@gmail.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../boot/dts/overlays/merus-amp-overlay.dts | 60 +
+ sound/soc/bcm/rpi-simple-soundcard.c | 28 +
+ sound/soc/codecs/Kconfig | 8 +
+ sound/soc/codecs/Makefile | 2 +
+ sound/soc/codecs/ma120x0p.c | 1384 +++++++++++++++++
+ 7 files changed, 1489 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/merus-amp-overlay.dts
+ create mode 100644 sound/soc/codecs/ma120x0p.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -103,6 +103,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ mcp3202.dtbo \
+ mcp342x.dtbo \
+ media-center.dtbo \
++ merus-amp.dtbo \
+ midi-uart0.dtbo \
+ midi-uart1.dtbo \
+ miniuart-bt.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1662,6 +1662,12 @@ Params: speed Display
+ (default "off")
+
+
++Name: merus-amp
++Info: Configures the merus-amp audio card
++Load: dtoverlay=merus-amp
++Params: <None>
++
++
+ Name: midi-uart0
+ Info: Configures UART0 (ttyAMA0) so that a requested 38.4kbaud actually gets
+ 31.25kbaud, the frequency required for MIDI
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/merus-amp-overlay.dts
+@@ -0,0 +1,60 @@
++// SPDX-License-Identifier: GPL-2.0-only
++// Definitions for Infineon Merus-Amp
++/dts-v1/;
++/plugin/;
++#include <dt-bindings/pinctrl/bcm2835.h>
++#include <dt-bindings/gpio/gpio.h>
++
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&gpio>;
++ __overlay__ {
++ merus_amp_pins: merus_amp_pins {
++ brcm,pins = <23>;
++ brcm,function = <0>; /* in */
++ brcm,pull = <2>; /* up */
++ };
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ merus_amp: ma120x0p@20 {
++ #sound-dai-cells = <0>;
++ compatible = "ma,ma120x0p";
++ reg = <0x20>;
++ status = "okay";
++ pinctrl-names = "default";
++ pinctrl-0 = <&merus_amp_pins>;
++ enable_gp-gpios = <&gpio 14 GPIO_ACTIVE_HIGH>;
++ mute_gp-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>;
++ booster_gp-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
++ error_gp-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>;
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "merus,merus-amp";
++ i2s-controller = <&i2s>;
++ status = "okay";
++ };
++ };
++};
+--- a/sound/soc/bcm/rpi-simple-soundcard.c
++++ b/sound/soc/bcm/rpi-simple-soundcard.c
+@@ -16,6 +16,10 @@
+ * adau1977-adc.c
+ * by Andrey Grodzovsky <andrey2805@gmail.com>
+ *
++ * merus-amp.c
++ * by Ariel Muszkat <ariel.muszkat@gmail.com>
++ * Jorgen Kragh Jakobsen <jorgen.kraghjakobsen@infineon.com>
++ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+@@ -229,6 +233,28 @@ static struct snd_rpi_simple_drvdata drv
+ .fixed_bclk_ratio = 64,
+ };
+
++SND_SOC_DAILINK_DEFS(merus_amp,
++ DAILINK_COMP_ARRAY(COMP_EMPTY()),
++ DAILINK_COMP_ARRAY(COMP_CODEC("ma120x0p-amp", "ma120x0p.1-0020")),
++ DAILINK_COMP_ARRAY(COMP_EMPTY()));
++
++static struct snd_soc_dai_link snd_merus_amp_dai[] = {
++ {
++ .name = "MerusAmp",
++ .stream_name = "Merus Audio Amp",
++ .dai_fmt = SND_SOC_DAIFMT_I2S |
++ SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ SND_SOC_DAILINK_REG(merus_amp),
++ },
++};
++
++static struct snd_rpi_simple_drvdata drvdata_merus_amp = {
++ .card_name = "snd_rpi_merus_amp",
++ .dai = snd_merus_amp_dai,
++ .fixed_bclk_ratio = 64,
++};
++
+ static const struct of_device_id snd_rpi_simple_of_match[] = {
+ { .compatible = "adi,adau1977-adc",
+ .data = (void *) &drvdata_adau1977 },
+@@ -241,6 +267,8 @@ static const struct of_device_id snd_rpi
+ { .compatible = "hifiberry,hifiberry-dac",
+ .data = (void *) &drvdata_hifiberry_dac },
+ { .compatible = "rpi,rpi-dac", &drvdata_rpi_dac},
++ { .compatible = "merus,merus-amp",
++ .data = (void *) &drvdata_merus_amp },
+ {},
+ };
+
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -103,6 +103,7 @@ config SND_SOC_ALL_CODECS
+ select SND_SOC_LM4857 if I2C
+ select SND_SOC_LM49453 if I2C
+ select SND_SOC_LOCHNAGAR_SC if MFD_LOCHNAGAR
++ select SND_SOC_MA120X0P if I2C
+ select SND_SOC_MAX98088 if I2C
+ select SND_SOC_MAX98090 if I2C
+ select SND_SOC_MAX98095 if I2C
+@@ -732,6 +733,13 @@ config SND_SOC_LOCHNAGAR_SC
+ This driver support the sound card functionality of the Cirrus
+ Logic Lochnagar audio development board.
+
++config SND_SOC_MA120X0P
++ tristate "Infineon Merus(TM) MA120X0P Multilevel Class-D Audio amplifiers"
++ depends on I2C
++ help
++ Enable support for Infineon MA120X0P Multilevel Class-D audio power
++ amplifiers.
++
+ config SND_SOC_MADERA
+ tristate
+ default y if SND_SOC_CS47L15=y
+--- a/sound/soc/codecs/Makefile
++++ b/sound/soc/codecs/Makefile
+@@ -99,6 +99,7 @@ snd-soc-l3-objs := l3.o
+ snd-soc-lm4857-objs := lm4857.o
+ snd-soc-lm49453-objs := lm49453.o
+ snd-soc-lochnagar-sc-objs := lochnagar-sc.o
++snd-soc-ma120x0p-objs := ma120x0p.o
+ snd-soc-madera-objs := madera.o
+ snd-soc-max9759-objs := max9759.o
+ snd-soc-max9768-objs := max9768.o
+@@ -386,6 +387,7 @@ obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
+ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
+ obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
+ obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o
++obj-$(CONFIG_SND_SOC_MA120X0P) += snd-soc-ma120x0p.o
+ obj-$(CONFIG_SND_SOC_MADERA) += snd-soc-madera.o
+ obj-$(CONFIG_SND_SOC_MAX9759) += snd-soc-max9759.o
+ obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
+--- /dev/null
++++ b/sound/soc/codecs/ma120x0p.c
+@@ -0,0 +1,1384 @@
++// SPDX-License-Identifier: GPL-2.0-or-later
++/*
++ * ASoC Driver for Infineon Merus(TM) ma120x0p multi-level class-D amplifier
++ *
++ * Authors: Ariel Muszkat <ariel.muszkat@gmail.com>
++ * Jorgen Kragh Jakobsen <jorgen.kraghjakobsen@infineon.com>
++ *
++ * Copyright (C) 2019 Infineon Technologies AG
++ *
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm_runtime.h>
++#include <linux/i2c.h>
++#include <linux/of_device.h>
++#include <linux/spi/spi.h>
++#include <linux/regmap.h>
++#include <linux/regulator/consumer.h>
++#include <linux/slab.h>
++#include <linux/gpio/consumer.h>
++#include <linux/gpio.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include <sound/tlv.h>
++#include <linux/interrupt.h>
++
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/uaccess.h>
++
++#ifndef _MA120X0P_
++#define _MA120X0P_
++//------------------------------------------------------------------manualPM---
++// Select Manual PowerMode control
++#define ma_manualpm__a 0
++#define ma_manualpm__len 1
++#define ma_manualpm__mask 0x40
++#define ma_manualpm__shift 0x06
++#define ma_manualpm__reset 0x00
++//--------------------------------------------------------------------pm_man---
++// manual selected power mode
++#define ma_pm_man__a 0
++#define ma_pm_man__len 2
++#define ma_pm_man__mask 0x30
++#define ma_pm_man__shift 0x04
++#define ma_pm_man__reset 0x03
++//------------------------------------------ ----------------------mthr_1to2---
++// mod. index threshold value for pm1=>pm2 change.
++#define ma_mthr_1to2__a 1
++#define ma_mthr_1to2__len 8
++#define ma_mthr_1to2__mask 0xff
++#define ma_mthr_1to2__shift 0x00
++#define ma_mthr_1to2__reset 0x3c
++//-----------------------------------------------------------------mthr_2to1---
++// mod. index threshold value for pm2=>pm1 change.
++#define ma_mthr_2to1__a 2
++#define ma_mthr_2to1__len 8
++#define ma_mthr_2to1__mask 0xff
++#define ma_mthr_2to1__shift 0x00
++#define ma_mthr_2to1__reset 0x32
++//-----------------------------------------------------------------mthr_2to3---
++// mod. index threshold value for pm2=>pm3 change.
++#define ma_mthr_2to3__a 3
++#define ma_mthr_2to3__len 8
++#define ma_mthr_2to3__mask 0xff
++#define ma_mthr_2to3__shift 0x00
++#define ma_mthr_2to3__reset 0x5a
++//-----------------------------------------------------------------mthr_3to2---
++// mod. index threshold value for pm3=>pm2 change.
++#define ma_mthr_3to2__a 4
++#define ma_mthr_3to2__len 8
++#define ma_mthr_3to2__mask 0xff
++#define ma_mthr_3to2__shift 0x00
++#define ma_mthr_3to2__reset 0x50
++//-------------------------------------------------------------pwmclkdiv_nom---
++// pwm default clock divider value
++#define ma_pwmclkdiv_nom__a 8
++#define ma_pwmclkdiv_nom__len 8
++#define ma_pwmclkdiv_nom__mask 0xff
++#define ma_pwmclkdiv_nom__shift 0x00
++#define ma_pwmclkdiv_nom__reset 0x26
++//--------- ----------------------------------------------------ocp_latch_en---
++// high to use permanently latching level-2 ocp
++#define ma_ocp_latch_en__a 10
++#define ma_ocp_latch_en__len 1
++#define ma_ocp_latch_en__mask 0x02
++#define ma_ocp_latch_en__shift 0x01
++#define ma_ocp_latch_en__reset 0x00
++//---------------------------------------------------------------lf_clamp_en---
++// high (default) to enable lf int2+3 clamping on clip
++#define ma_lf_clamp_en__a 10
++#define ma_lf_clamp_en__len 1
++#define ma_lf_clamp_en__mask 0x80
++#define ma_lf_clamp_en__shift 0x07
++#define ma_lf_clamp_en__reset 0x00
++//-------------------------------------------------------pmcfg_btl_b.modtype---
++//
++#define ma_pmcfg_btl_b__modtype__a 18
++#define ma_pmcfg_btl_b__modtype__len 2
++#define ma_pmcfg_btl_b__modtype__mask 0x18
++#define ma_pmcfg_btl_b__modtype__shift 0x03
++#define ma_pmcfg_btl_b__modtype__reset 0x02
++//-------------------------------------------------------pmcfg_btl_b.freqdiv---
++#define ma_pmcfg_btl_b__freqdiv__a 18
++#define ma_pmcfg_btl_b__freqdiv__len 2
++#define ma_pmcfg_btl_b__freqdiv__mask 0x06
++#define ma_pmcfg_btl_b__freqdiv__shift 0x01
++#define ma_pmcfg_btl_b__freqdiv__reset 0x01
++//----------------------------------------------------pmcfg_btl_b.lf_gain_ol---
++//
++#define ma_pmcfg_btl_b__lf_gain_ol__a 18
++#define ma_pmcfg_btl_b__lf_gain_ol__len 1
++#define ma_pmcfg_btl_b__lf_gain_ol__mask 0x01
++#define ma_pmcfg_btl_b__lf_gain_ol__shift 0x00
++#define ma_pmcfg_btl_b__lf_gain_ol__reset 0x01
++//-------------------------------------------------------pmcfg_btl_c.freqdiv---
++//
++#define ma_pmcfg_btl_c__freqdiv__a 19
++#define ma_pmcfg_btl_c__freqdiv__len 2
++#define ma_pmcfg_btl_c__freqdiv__mask 0x06
++#define ma_pmcfg_btl_c__freqdiv__shift 0x01
++#define ma_pmcfg_btl_c__freqdiv__reset 0x01
++//-------------------------------------------------------pmcfg_btl_c.modtype---
++//
++#define ma_pmcfg_btl_c__modtype__a 19
++#define ma_pmcfg_btl_c__modtype__len 2
++#define ma_pmcfg_btl_c__modtype__mask 0x18
++#define ma_pmcfg_btl_c__modtype__shift 0x03
++#define ma_pmcfg_btl_c__modtype__reset 0x01
++//----------------------------------------------------pmcfg_btl_c.lf_gain_ol---
++//
++#define ma_pmcfg_btl_c__lf_gain_ol__a 19
++#define ma_pmcfg_btl_c__lf_gain_ol__len 1
++#define ma_pmcfg_btl_c__lf_gain_ol__mask 0x01
++#define ma_pmcfg_btl_c__lf_gain_ol__shift 0x00
++#define ma_pmcfg_btl_c__lf_gain_ol__reset 0x00
++//-------------------------------------------------------pmcfg_btl_d.modtype---
++//
++#define ma_pmcfg_btl_d__modtype__a 20
++#define ma_pmcfg_btl_d__modtype__len 2
++#define ma_pmcfg_btl_d__modtype__mask 0x18
++#define ma_pmcfg_btl_d__modtype__shift 0x03
++#define ma_pmcfg_btl_d__modtype__reset 0x02
++//-------------------------------------------------------pmcfg_btl_d.freqdiv---
++//
++#define ma_pmcfg_btl_d__freqdiv__a 20
++#define ma_pmcfg_btl_d__freqdiv__len 2
++#define ma_pmcfg_btl_d__freqdiv__mask 0x06
++#define ma_pmcfg_btl_d__freqdiv__shift 0x01
++#define ma_pmcfg_btl_d__freqdiv__reset 0x02
++//----------------------------------------------------pmcfg_btl_d.lf_gain_ol---
++//
++#define ma_pmcfg_btl_d__lf_gain_ol__a 20
++#define ma_pmcfg_btl_d__lf_gain_ol__len 1
++#define ma_pmcfg_btl_d__lf_gain_ol__mask 0x01
++#define ma_pmcfg_btl_d__lf_gain_ol__shift 0x00
++#define ma_pmcfg_btl_d__lf_gain_ol__reset 0x00
++//------------ -------------------------------------------pmcfg_se_a.modtype---
++//
++#define ma_pmcfg_se_a__modtype__a 21
++#define ma_pmcfg_se_a__modtype__len 2
++#define ma_pmcfg_se_a__modtype__mask 0x18
++#define ma_pmcfg_se_a__modtype__shift 0x03
++#define ma_pmcfg_se_a__modtype__reset 0x01
++//--------------------------------------------------------pmcfg_se_a.freqdiv---
++//
++#define ma_pmcfg_se_a__freqdiv__a 21
++#define ma_pmcfg_se_a__freqdiv__len 2
++#define ma_pmcfg_se_a__freqdiv__mask 0x06
++#define ma_pmcfg_se_a__freqdiv__shift 0x01
++#define ma_pmcfg_se_a__freqdiv__reset 0x00
++//-----------------------------------------------------pmcfg_se_a.lf_gain_ol---
++//
++#define ma_pmcfg_se_a__lf_gain_ol__a 21
++#define ma_pmcfg_se_a__lf_gain_ol__len 1
++#define ma_pmcfg_se_a__lf_gain_ol__mask 0x01
++#define ma_pmcfg_se_a__lf_gain_ol__shift 0x00
++#define ma_pmcfg_se_a__lf_gain_ol__reset 0x01
++//-----------------------------------------------------pmcfg_se_b.lf_gain_ol---
++//
++#define ma_pmcfg_se_b__lf_gain_ol__a 22
++#define ma_pmcfg_se_b__lf_gain_ol__len 1
++#define ma_pmcfg_se_b__lf_gain_ol__mask 0x01
++#define ma_pmcfg_se_b__lf_gain_ol__shift 0x00
++#define ma_pmcfg_se_b__lf_gain_ol__reset 0x00
++//--------------------------------------------------------pmcfg_se_b.freqdiv---
++//
++#define ma_pmcfg_se_b__freqdiv__a 22
++#define ma_pmcfg_se_b__freqdiv__len 2
++#define ma_pmcfg_se_b__freqdiv__mask 0x06
++#define ma_pmcfg_se_b__freqdiv__shift 0x01
++#define ma_pmcfg_se_b__freqdiv__reset 0x01
++//--------------------------------------------------------pmcfg_se_b.modtype---
++//
++#define ma_pmcfg_se_b__modtype__a 22
++#define ma_pmcfg_se_b__modtype__len 2
++#define ma_pmcfg_se_b__modtype__mask 0x18
++#define ma_pmcfg_se_b__modtype__shift 0x03
++#define ma_pmcfg_se_b__modtype__reset 0x01
++//----------------------------------------------------------balwaitcount_pm1---
++// pm1 balancing period.
++#define ma_balwaitcount_pm1__a 23
++#define ma_balwaitcount_pm1__len 8
++#define ma_balwaitcount_pm1__mask 0xff
++#define ma_balwaitcount_pm1__shift 0x00
++#define ma_balwaitcount_pm1__reset 0x14
++//----------------------------------------------------------balwaitcount_pm2---
++// pm2 balancing period.
++#define ma_balwaitcount_pm2__a 24
++#define ma_balwaitcount_pm2__len 8
++#define ma_balwaitcount_pm2__mask 0xff
++#define ma_balwaitcount_pm2__shift 0x00
++#define ma_balwaitcount_pm2__reset 0x14
++//----------------------------------------------------------balwaitcount_pm3---
++// pm3 balancing period.
++#define ma_balwaitcount_pm3__a 25
++#define ma_balwaitcount_pm3__len 8
++#define ma_balwaitcount_pm3__mask 0xff
++#define ma_balwaitcount_pm3__shift 0x00
++#define ma_balwaitcount_pm3__reset 0x1a
++//-------------------------------------------------------------usespread_pm1---
++// pm1 pwm spread-spectrum mode on/off.
++#define ma_usespread_pm1__a 26
++#define ma_usespread_pm1__len 1
++#define ma_usespread_pm1__mask 0x40
++#define ma_usespread_pm1__shift 0x06
++#define ma_usespread_pm1__reset 0x00
++//---------------------------------------------------------------dtsteps_pm1---
++// pm1 dead time setting [10ns steps].
++#define ma_dtsteps_pm1__a 26
++#define ma_dtsteps_pm1__len 3
++#define ma_dtsteps_pm1__mask 0x38
++#define ma_dtsteps_pm1__shift 0x03
++#define ma_dtsteps_pm1__reset 0x04
++//---------------------------------------------------------------baltype_pm1---
++// pm1 balancing sensor scheme.
++#define ma_baltype_pm1__a 26
++#define ma_baltype_pm1__len 3
++#define ma_baltype_pm1__mask 0x07
++#define ma_baltype_pm1__shift 0x00
++#define ma_baltype_pm1__reset 0x00
++//-------------------------------------------------------------usespread_pm2---
++// pm2 pwm spread-spectrum mode on/off.
++#define ma_usespread_pm2__a 27
++#define ma_usespread_pm2__len 1
++#define ma_usespread_pm2__mask 0x40
++#define ma_usespread_pm2__shift 0x06
++#define ma_usespread_pm2__reset 0x00
++//---------------------------------------------------------------dtsteps_pm2---
++// pm2 dead time setting [10ns steps].
++#define ma_dtsteps_pm2__a 27
++#define ma_dtsteps_pm2__len 3
++#define ma_dtsteps_pm2__mask 0x38
++#define ma_dtsteps_pm2__shift 0x03
++#define ma_dtsteps_pm2__reset 0x03
++//---------------------------------------------------------------baltype_pm2---
++// pm2 balancing sensor scheme.
++#define ma_baltype_pm2__a 27
++#define ma_baltype_pm2__len 3
++#define ma_baltype_pm2__mask 0x07
++#define ma_baltype_pm2__shift 0x00
++#define ma_baltype_pm2__reset 0x01
++//-------------------------------------------------------------usespread_pm3---
++// pm3 pwm spread-spectrum mode on/off.
++#define ma_usespread_pm3__a 28
++#define ma_usespread_pm3__len 1
++#define ma_usespread_pm3__mask 0x40
++#define ma_usespread_pm3__shift 0x06
++#define ma_usespread_pm3__reset 0x00
++//---------------------------------------------------------------dtsteps_pm3---
++// pm3 dead time setting [10ns steps].
++#define ma_dtsteps_pm3__a 28
++#define ma_dtsteps_pm3__len 3
++#define ma_dtsteps_pm3__mask 0x38
++#define ma_dtsteps_pm3__shift 0x03
++#define ma_dtsteps_pm3__reset 0x01
++//---------------------------------------------------------------baltype_pm3---
++// pm3 balancing sensor scheme.
++#define ma_baltype_pm3__a 28
++#define ma_baltype_pm3__len 3
++#define ma_baltype_pm3__mask 0x07
++#define ma_baltype_pm3__shift 0x00
++#define ma_baltype_pm3__reset 0x03
++//-----------------------------------------------------------------pmprofile---
++// pm profile select. valid presets: 0-1-2-3-4. 5=> custom profile.
++#define ma_pmprofile__a 29
++#define ma_pmprofile__len 3
++#define ma_pmprofile__mask 0x07
++#define ma_pmprofile__shift 0x00
++#define ma_pmprofile__reset 0x00
++//-------------------------------------------------------------------pm3_man---
++// custom profile pm3 contents. 0=>a, 1=>b, 2=>c, 3=>d
++#define ma_pm3_man__a 30
++#define ma_pm3_man__len 2
++#define ma_pm3_man__mask 0x30
++#define ma_pm3_man__shift 0x04
++#define ma_pm3_man__reset 0x02
++//-------------------------------------------------------------------pm2_man---
++// custom profile pm2 contents. 0=>a, 1=>b, 2=>c, 3=>d
++#define ma_pm2_man__a 30
++#define ma_pm2_man__len 2
++#define ma_pm2_man__mask 0x0c
++#define ma_pm2_man__shift 0x02
++#define ma_pm2_man__reset 0x03
++//-------------------------------------------------------------------pm1_man---
++// custom profile pm1 contents. 0=>a, 1=>b, 2=>c, 3=>d
++#define ma_pm1_man__a 30
++#define ma_pm1_man__len 2
++#define ma_pm1_man__mask 0x03
++#define ma_pm1_man__shift 0x00
++#define ma_pm1_man__reset 0x03
++//-----------------------------------------------------------ocp_latch_clear---
++// low-high clears current ocp latched condition.
++#define ma_ocp_latch_clear__a 32
++#define ma_ocp_latch_clear__len 1
++#define ma_ocp_latch_clear__mask 0x80
++#define ma_ocp_latch_clear__shift 0x07
++#define ma_ocp_latch_clear__reset 0x00
++//-------------------------------------------------------------audio_in_mode---
++// audio input mode; 0-1-2-3-4-5
++#define ma_audio_in_mode__a 37
++#define ma_audio_in_mode__len 3
++#define ma_audio_in_mode__mask 0xe0
++#define ma_audio_in_mode__shift 0x05
++#define ma_audio_in_mode__reset 0x00
++//-----------------------------------------------------------------eh_dcshdn---
++// high to enable dc protection
++#define ma_eh_dcshdn__a 38
++#define ma_eh_dcshdn__len 1
++#define ma_eh_dcshdn__mask 0x04
++#define ma_eh_dcshdn__shift 0x02
++#define ma_eh_dcshdn__reset 0x01
++//---------------------------------------------------------audio_in_mode_ext---
++// if set, audio_in_mode is controlled from audio_in_mode register. if not set
++//audio_in_mode is set from fuse bank setting
++#define ma_audio_in_mode_ext__a 39
++#define ma_audio_in_mode_ext__len 1
++#define ma_audio_in_mode_ext__mask 0x20
++#define ma_audio_in_mode_ext__shift 0x05
++#define ma_audio_in_mode_ext__reset 0x00
++//------------------------------------------------------------------eh_clear---
++// flip to clear error registers
++#define ma_eh_clear__a 45
++#define ma_eh_clear__len 1
++#define ma_eh_clear__mask 0x04
++#define ma_eh_clear__shift 0x02
++#define ma_eh_clear__reset 0x00
++//----------------------------------------------------------thermal_compr_en---
++// enable otw-contr. input compression?
++#define ma_thermal_compr_en__a 45
++#define ma_thermal_compr_en__len 1
++#define ma_thermal_compr_en__mask 0x20
++#define ma_thermal_compr_en__shift 0x05
++#define ma_thermal_compr_en__reset 0x01
++//---------------------------------------------------------------system_mute---
++// 1 = mute system, 0 = normal operation
++#define ma_system_mute__a 45
++#define ma_system_mute__len 1
++#define ma_system_mute__mask 0x40
++#define ma_system_mute__shift 0x06
++#define ma_system_mute__reset 0x00
++//------------------------------------------------------thermal_compr_max_db---
++// audio limiter max thermal reduction
++#define ma_thermal_compr_max_db__a 46
++#define ma_thermal_compr_max_db__len 3
++#define ma_thermal_compr_max_db__mask 0x07
++#define ma_thermal_compr_max_db__shift 0x00
++#define ma_thermal_compr_max_db__reset 0x04
++//---------------------------------------------------------audio_proc_enable---
++// enable audio proc, bypass if not enabled
++#define ma_audio_proc_enable__a 53
++#define ma_audio_proc_enable__len 1
++#define ma_audio_proc_enable__mask 0x08
++#define ma_audio_proc_enable__shift 0x03
++#define ma_audio_proc_enable__reset 0x00
++//--------------------------------------------------------audio_proc_release---
++// 00:slow, 01:normal, 10:fast
++#define ma_audio_proc_release__a 53
++#define ma_audio_proc_release__len 2
++#define ma_audio_proc_release__mask 0x30
++#define ma_audio_proc_release__shift 0x04
++#define ma_audio_proc_release__reset 0x00
++//---------------------------------------------------------audio_proc_attack---
++// 00:slow, 01:normal, 10:fast
++#define ma_audio_proc_attack__a 53
++#define ma_audio_proc_attack__len 2
++#define ma_audio_proc_attack__mask 0xc0
++#define ma_audio_proc_attack__shift 0x06
++#define ma_audio_proc_attack__reset 0x00
++//----------------------------------------------------------------i2s_format---
++// i2s basic data format, 000 = std. i2s, 001 = left justified (default)
++#define ma_i2s_format__a 53
++#define ma_i2s_format__len 3
++#define ma_i2s_format__mask 0x07
++#define ma_i2s_format__shift 0x00
++#define ma_i2s_format__reset 0x01
++//--------------------------------------------------audio_proc_limiterenable---
++// 1: enable limiter, 0: disable limiter
++#define ma_audio_proc_limiterenable__a 54
++#define ma_audio_proc_limiterenable__len 1
++#define ma_audio_proc_limiterenable__mask 0x40
++#define ma_audio_proc_limiterenable__shift 0x06
++#define ma_audio_proc_limiterenable__reset 0x00
++//-----------------------------------------------------------audio_proc_mute---
++// 1: mute, 0: unmute
++#define ma_audio_proc_mute__a 54
++#define ma_audio_proc_mute__len 1
++#define ma_audio_proc_mute__mask 0x80
++#define ma_audio_proc_mute__shift 0x07
++#define ma_audio_proc_mute__reset 0x00
++//---------------------------------------------------------------i2s_sck_pol---
++// i2s sck polarity cfg. 0 = rising edge data change
++#define ma_i2s_sck_pol__a 54
++#define ma_i2s_sck_pol__len 1
++#define ma_i2s_sck_pol__mask 0x01
++#define ma_i2s_sck_pol__shift 0x00
++#define ma_i2s_sck_pol__reset 0x01
++//-------------------------------------------------------------i2s_framesize---
++// i2s word length. 00 = 32bit, 01 = 24bit
++#define ma_i2s_framesize__a 54
++#define ma_i2s_framesize__len 2
++#define ma_i2s_framesize__mask 0x18
++#define ma_i2s_framesize__shift 0x03
++#define ma_i2s_framesize__reset 0x00
++//----------------------------------------------------------------i2s_ws_pol---
++// i2s ws polarity. 0 = low first
++#define ma_i2s_ws_pol__a 54
++#define ma_i2s_ws_pol__len 1
++#define ma_i2s_ws_pol__mask 0x02
++#define ma_i2s_ws_pol__shift 0x01
++#define ma_i2s_ws_pol__reset 0x00
++//-----------------------------------------------------------------i2s_order---
++// i2s word bit order. 0 = msb first
++#define ma_i2s_order__a 54
++#define ma_i2s_order__len 1
++#define ma_i2s_order__mask 0x04
++#define ma_i2s_order__shift 0x02
++#define ma_i2s_order__reset 0x00
++//------------------------------------------------------------i2s_rightfirst---
++// i2s l/r word order; 0 = left first
++#define ma_i2s_rightfirst__a 54
++#define ma_i2s_rightfirst__len 1
++#define ma_i2s_rightfirst__mask 0x20
++#define ma_i2s_rightfirst__shift 0x05
++#define ma_i2s_rightfirst__reset 0x00
++//-------------------------------------------------------------vol_db_master---
++// master volume db
++#define ma_vol_db_master__a 64
++#define ma_vol_db_master__len 8
++#define ma_vol_db_master__mask 0xff
++#define ma_vol_db_master__shift 0x00
++#define ma_vol_db_master__reset 0x18
++//------------------------------------------------------------vol_lsb_master---
++// master volume lsb 1/4 steps
++#define ma_vol_lsb_master__a 65
++#define ma_vol_lsb_master__len 2
++#define ma_vol_lsb_master__mask 0x03
++#define ma_vol_lsb_master__shift 0x00
++#define ma_vol_lsb_master__reset 0x00
++//----------------------------------------------------------------vol_db_ch0---
++// volume channel 0
++#define ma_vol_db_ch0__a 66
++#define ma_vol_db_ch0__len 8
++#define ma_vol_db_ch0__mask 0xff
++#define ma_vol_db_ch0__shift 0x00
++#define ma_vol_db_ch0__reset 0x18
++//----------------------------------------------------------------vol_db_ch1---
++// volume channel 1
++#define ma_vol_db_ch1__a 67
++#define ma_vol_db_ch1__len 8
++#define ma_vol_db_ch1__mask 0xff
++#define ma_vol_db_ch1__shift 0x00
++#define ma_vol_db_ch1__reset 0x18
++//----------------------------------------------------------------vol_db_ch2---
++// volume channel 2
++#define ma_vol_db_ch2__a 68
++#define ma_vol_db_ch2__len 8
++#define ma_vol_db_ch2__mask 0xff
++#define ma_vol_db_ch2__shift 0x00
++#define ma_vol_db_ch2__reset 0x18
++//----------------------------------------------------------------vol_db_ch3---
++// volume channel 3
++#define ma_vol_db_ch3__a 69
++#define ma_vol_db_ch3__len 8
++#define ma_vol_db_ch3__mask 0xff
++#define ma_vol_db_ch3__shift 0x00
++#define ma_vol_db_ch3__reset 0x18
++//---------------------------------------------------------------vol_lsb_ch0---
++// volume channel 1 - 1/4 steps
++#define ma_vol_lsb_ch0__a 70
++#define ma_vol_lsb_ch0__len 2
++#define ma_vol_lsb_ch0__mask 0x03
++#define ma_vol_lsb_ch0__shift 0x00
++#define ma_vol_lsb_ch0__reset 0x00
++//---------------------------------------------------------------vol_lsb_ch1---
++// volume channel 3 - 1/4 steps
++#define ma_vol_lsb_ch1__a 70
++#define ma_vol_lsb_ch1__len 2
++#define ma_vol_lsb_ch1__mask 0x0c
++#define ma_vol_lsb_ch1__shift 0x02
++#define ma_vol_lsb_ch1__reset 0x00
++//---------------------------------------------------------------vol_lsb_ch2---
++// volume channel 2 - 1/4 steps
++#define ma_vol_lsb_ch2__a 70
++#define ma_vol_lsb_ch2__len 2
++#define ma_vol_lsb_ch2__mask 0x30
++#define ma_vol_lsb_ch2__shift 0x04
++#define ma_vol_lsb_ch2__reset 0x00
++//---------------------------------------------------------------vol_lsb_ch3---
++// volume channel 3 - 1/4 steps
++#define ma_vol_lsb_ch3__a 70
++#define ma_vol_lsb_ch3__len 2
++#define ma_vol_lsb_ch3__mask 0xc0
++#define ma_vol_lsb_ch3__shift 0x06
++#define ma_vol_lsb_ch3__reset 0x00
++//----------------------------------------------------------------thr_db_ch0---
++// thr_db channel 0
++#define ma_thr_db_ch0__a 71
++#define ma_thr_db_ch0__len 8
++#define ma_thr_db_ch0__mask 0xff
++#define ma_thr_db_ch0__shift 0x00
++#define ma_thr_db_ch0__reset 0x18
++//----------------------------------------------------------------thr_db_ch1---
++// thr db ch1
++#define ma_thr_db_ch1__a 72
++#define ma_thr_db_ch1__len 8
++#define ma_thr_db_ch1__mask 0xff
++#define ma_thr_db_ch1__shift 0x00
++#define ma_thr_db_ch1__reset 0x18
++//----------------------------------------------------------------thr_db_ch2---
++// thr db ch2
++#define ma_thr_db_ch2__a 73
++#define ma_thr_db_ch2__len 8
++#define ma_thr_db_ch2__mask 0xff
++#define ma_thr_db_ch2__shift 0x00
++#define ma_thr_db_ch2__reset 0x18
++//----------------------------------------------------------------thr_db_ch3---
++// threshold db ch3
++#define ma_thr_db_ch3__a 74
++#define ma_thr_db_ch3__len 8
++#define ma_thr_db_ch3__mask 0xff
++#define ma_thr_db_ch3__shift 0x00
++#define ma_thr_db_ch3__reset 0x18
++//---------------------------------------------------------------thr_lsb_ch0---
++// thr lsb ch0
++#define ma_thr_lsb_ch0__a 75
++#define ma_thr_lsb_ch0__len 2
++#define ma_thr_lsb_ch0__mask 0x03
++#define ma_thr_lsb_ch0__shift 0x00
++#define ma_thr_lsb_ch0__reset 0x00
++//---------------------------------------------------------------thr_lsb_ch1---
++// thr lsb ch1
++#define ma_thr_lsb_ch1__a 75
++#define ma_thr_lsb_ch1__len 2
++#define ma_thr_lsb_ch1__mask 0x0c
++#define ma_thr_lsb_ch1__shift 0x02
++#define ma_thr_lsb_ch1__reset 0x00
++//---------------------------------------------------------------thr_lsb_ch2---
++// thr lsb ch2 1/4 db step
++#define ma_thr_lsb_ch2__a 75
++#define ma_thr_lsb_ch2__len 2
++#define ma_thr_lsb_ch2__mask 0x30
++#define ma_thr_lsb_ch2__shift 0x04
++#define ma_thr_lsb_ch2__reset 0x00
++//---------------------------------------------------------------thr_lsb_ch3---
++// threshold lsb ch3
++#define ma_thr_lsb_ch3__a 75
++#define ma_thr_lsb_ch3__len 2
++#define ma_thr_lsb_ch3__mask 0xc0
++#define ma_thr_lsb_ch3__shift 0x06
++#define ma_thr_lsb_ch3__reset 0x00
++//-----------------------------------------------------------dcu_mon0.pm_mon---
++// power mode monitor channel 0
++#define ma_dcu_mon0__pm_mon__a 96
++#define ma_dcu_mon0__pm_mon__len 2
++#define ma_dcu_mon0__pm_mon__mask 0x03
++#define ma_dcu_mon0__pm_mon__shift 0x00
++#define ma_dcu_mon0__pm_mon__reset 0x00
++//-----------------------------------------------------dcu_mon0.freqmode_mon---
++// frequence mode monitor channel 0
++#define ma_dcu_mon0__freqmode_mon__a 96
++#define ma_dcu_mon0__freqmode_mon__len 3
++#define ma_dcu_mon0__freqmode_mon__mask 0x70
++#define ma_dcu_mon0__freqmode_mon__shift 0x04
++#define ma_dcu_mon0__freqmode_mon__reset 0x00
++//-------------------------------------------------------dcu_mon0.pps_passed---
++// dcu0 pps completion indicator
++#define ma_dcu_mon0__pps_passed__a 96
++#define ma_dcu_mon0__pps_passed__len 1
++#define ma_dcu_mon0__pps_passed__mask 0x80
++#define ma_dcu_mon0__pps_passed__shift 0x07
++#define ma_dcu_mon0__pps_passed__reset 0x00
++//----------------------------------------------------------dcu_mon0.ocp_mon---
++// ocp monitor channel 0
++#define ma_dcu_mon0__ocp_mon__a 97
++#define ma_dcu_mon0__ocp_mon__len 1
++#define ma_dcu_mon0__ocp_mon__mask 0x01
++#define ma_dcu_mon0__ocp_mon__shift 0x00
++#define ma_dcu_mon0__ocp_mon__reset 0x00
++//--------------------------------------------------------dcu_mon0.vcfly1_ok---
++// cfly1 protection monitor channel 0.
++#define ma_dcu_mon0__vcfly1_ok__a 97
++#define ma_dcu_mon0__vcfly1_ok__len 1
++#define ma_dcu_mon0__vcfly1_ok__mask 0x02
++#define ma_dcu_mon0__vcfly1_ok__shift 0x01
++#define ma_dcu_mon0__vcfly1_ok__reset 0x00
++//--------------------------------------------------------dcu_mon0.vcfly2_ok---
++// cfly2 protection monitor channel 0.
++#define ma_dcu_mon0__vcfly2_ok__a 97
++#define ma_dcu_mon0__vcfly2_ok__len 1
++#define ma_dcu_mon0__vcfly2_ok__mask 0x04
++#define ma_dcu_mon0__vcfly2_ok__shift 0x02
++#define ma_dcu_mon0__vcfly2_ok__reset 0x00
++//----------------------------------------------------------dcu_mon0.pvdd_ok---
++// dcu0 pvdd monitor
++#define ma_dcu_mon0__pvdd_ok__a 97
++#define ma_dcu_mon0__pvdd_ok__len 1
++#define ma_dcu_mon0__pvdd_ok__mask 0x08
++#define ma_dcu_mon0__pvdd_ok__shift 0x03
++#define ma_dcu_mon0__pvdd_ok__reset 0x00
++//-----------------------------------------------------------dcu_mon0.vdd_ok---
++// dcu0 vdd monitor
++#define ma_dcu_mon0__vdd_ok__a 97
++#define ma_dcu_mon0__vdd_ok__len 1
++#define ma_dcu_mon0__vdd_ok__mask 0x10
++#define ma_dcu_mon0__vdd_ok__shift 0x04
++#define ma_dcu_mon0__vdd_ok__reset 0x00
++//-------------------------------------------------------------dcu_mon0.mute---
++// dcu0 mute monitor
++#define ma_dcu_mon0__mute__a 97
++#define ma_dcu_mon0__mute__len 1
++#define ma_dcu_mon0__mute__mask 0x20
++#define ma_dcu_mon0__mute__shift 0x05
++#define ma_dcu_mon0__mute__reset 0x00
++//------------------------------------------------------------dcu_mon0.m_mon---
++// m sense monitor channel 0
++#define ma_dcu_mon0__m_mon__a 98
++#define ma_dcu_mon0__m_mon__len 8
++#define ma_dcu_mon0__m_mon__mask 0xff
++#define ma_dcu_mon0__m_mon__shift 0x00
++#define ma_dcu_mon0__m_mon__reset 0x00
++//-----------------------------------------------------------dcu_mon1.pm_mon---
++// power mode monitor channel 1
++#define ma_dcu_mon1__pm_mon__a 100
++#define ma_dcu_mon1__pm_mon__len 2
++#define ma_dcu_mon1__pm_mon__mask 0x03
++#define ma_dcu_mon1__pm_mon__shift 0x00
++#define ma_dcu_mon1__pm_mon__reset 0x00
++//-----------------------------------------------------dcu_mon1.freqmode_mon---
++// frequence mode monitor channel 1
++#define ma_dcu_mon1__freqmode_mon__a 100
++#define ma_dcu_mon1__freqmode_mon__len 3
++#define ma_dcu_mon1__freqmode_mon__mask 0x70
++#define ma_dcu_mon1__freqmode_mon__shift 0x04
++#define ma_dcu_mon1__freqmode_mon__reset 0x00
++//-------------------------------------------------------dcu_mon1.pps_passed---
++// dcu1 pps completion indicator
++#define ma_dcu_mon1__pps_passed__a 100
++#define ma_dcu_mon1__pps_passed__len 1
++#define ma_dcu_mon1__pps_passed__mask 0x80
++#define ma_dcu_mon1__pps_passed__shift 0x07
++#define ma_dcu_mon1__pps_passed__reset 0x00
++//----------------------------------------------------------dcu_mon1.ocp_mon---
++// ocp monitor channel 1
++#define ma_dcu_mon1__ocp_mon__a 101
++#define ma_dcu_mon1__ocp_mon__len 1
++#define ma_dcu_mon1__ocp_mon__mask 0x01
++#define ma_dcu_mon1__ocp_mon__shift 0x00
++#define ma_dcu_mon1__ocp_mon__reset 0x00
++//--------------------------------------------------------dcu_mon1.vcfly1_ok---
++// cfly1 protcetion monitor channel 1
++#define ma_dcu_mon1__vcfly1_ok__a 101
++#define ma_dcu_mon1__vcfly1_ok__len 1
++#define ma_dcu_mon1__vcfly1_ok__mask 0x02
++#define ma_dcu_mon1__vcfly1_ok__shift 0x01
++#define ma_dcu_mon1__vcfly1_ok__reset 0x00
++//--------------------------------------------------------dcu_mon1.vcfly2_ok---
++// cfly2 protection monitor channel 1
++#define ma_dcu_mon1__vcfly2_ok__a 101
++#define ma_dcu_mon1__vcfly2_ok__len 1
++#define ma_dcu_mon1__vcfly2_ok__mask 0x04
++#define ma_dcu_mon1__vcfly2_ok__shift 0x02
++#define ma_dcu_mon1__vcfly2_ok__reset 0x00
++//----------------------------------------------------------dcu_mon1.pvdd_ok---
++// dcu1 pvdd monitor
++#define ma_dcu_mon1__pvdd_ok__a 101
++#define ma_dcu_mon1__pvdd_ok__len 1
++#define ma_dcu_mon1__pvdd_ok__mask 0x08
++#define ma_dcu_mon1__pvdd_ok__shift 0x03
++#define ma_dcu_mon1__pvdd_ok__reset 0x00
++//-----------------------------------------------------------dcu_mon1.vdd_ok---
++// dcu1 vdd monitor
++#define ma_dcu_mon1__vdd_ok__a 101
++#define ma_dcu_mon1__vdd_ok__len 1
++#define ma_dcu_mon1__vdd_ok__mask 0x10
++#define ma_dcu_mon1__vdd_ok__shift 0x04
++#define ma_dcu_mon1__vdd_ok__reset 0x00
++//-------------------------------------------------------------dcu_mon1.mute---
++// dcu1 mute monitor
++#define ma_dcu_mon1__mute__a 101
++#define ma_dcu_mon1__mute__len 1
++#define ma_dcu_mon1__mute__mask 0x20
++#define ma_dcu_mon1__mute__shift 0x05
++#define ma_dcu_mon1__mute__reset 0x00
++//------------------------------------------------------------dcu_mon1.m_mon---
++// m sense monitor channel 1
++#define ma_dcu_mon1__m_mon__a 102
++#define ma_dcu_mon1__m_mon__len 8
++#define ma_dcu_mon1__m_mon__mask 0xff
++#define ma_dcu_mon1__m_mon__shift 0x00
++#define ma_dcu_mon1__m_mon__reset 0x00
++//--------------------------------------------------------dcu_mon0.sw_enable---
++// dcu0 switch enable monitor
++#define ma_dcu_mon0__sw_enable__a 104
++#define ma_dcu_mon0__sw_enable__len 1
++#define ma_dcu_mon0__sw_enable__mask 0x40
++#define ma_dcu_mon0__sw_enable__shift 0x06
++#define ma_dcu_mon0__sw_enable__reset 0x00
++//--------------------------------------------------------dcu_mon1.sw_enable---
++// dcu1 switch enable monitor
++#define ma_dcu_mon1__sw_enable__a 104
++#define ma_dcu_mon1__sw_enable__len 1
++#define ma_dcu_mon1__sw_enable__mask 0x80
++#define ma_dcu_mon1__sw_enable__shift 0x07
++#define ma_dcu_mon1__sw_enable__reset 0x00
++//------------------------------------------------------------hvboot0_ok_mon---
++// hvboot0_ok for test/debug
++#define ma_hvboot0_ok_mon__a 105
++#define ma_hvboot0_ok_mon__len 1
++#define ma_hvboot0_ok_mon__mask 0x40
++#define ma_hvboot0_ok_mon__shift 0x06
++#define ma_hvboot0_ok_mon__reset 0x00
++//------------------------------------------------------------hvboot1_ok_mon---
++// hvboot1_ok for test/debug
++#define ma_hvboot1_ok_mon__a 105
++#define ma_hvboot1_ok_mon__len 1
++#define ma_hvboot1_ok_mon__mask 0x80
++#define ma_hvboot1_ok_mon__shift 0x07
++#define ma_hvboot1_ok_mon__reset 0x00
++//-----------------------------------------------------------------error_acc---
++// accumulated errors, at and after triggering
++#define ma_error_acc__a 109
++#define ma_error_acc__len 8
++#define ma_error_acc__mask 0xff
++#define ma_error_acc__shift 0x00
++#define ma_error_acc__reset 0x00
++//-------------------------------------------------------------i2s_data_rate---
++// detected i2s data rate: 00/01/10 = x1/x2/x4
++#define ma_i2s_data_rate__a 116
++#define ma_i2s_data_rate__len 2
++#define ma_i2s_data_rate__mask 0x03
++#define ma_i2s_data_rate__shift 0x00
++#define ma_i2s_data_rate__reset 0x00
++//---------------------------------------------------------audio_in_mode_mon---
++// audio input mode monitor
++#define ma_audio_in_mode_mon__a 116
++#define ma_audio_in_mode_mon__len 3
++#define ma_audio_in_mode_mon__mask 0x1c
++#define ma_audio_in_mode_mon__shift 0x02
++#define ma_audio_in_mode_mon__reset 0x00
++//------------------------------------------------------------------msel_mon---
++// msel[2:0] monitor register
++#define ma_msel_mon__a 117
++#define ma_msel_mon__len 3
++#define ma_msel_mon__mask 0x07
++#define ma_msel_mon__shift 0x00
++#define ma_msel_mon__reset 0x00
++//---------------------------------------------------------------------error---
++// current error flag monitor reg - for app. ctrl.
++#define ma_error__a 124
++#define ma_error__len 8
++#define ma_error__mask 0xff
++#define ma_error__shift 0x00
++#define ma_error__reset 0x00
++//----------------------------------------------------audio_proc_limiter_mon---
++// b7-b4: channel 3-0 limiter active
++#define ma_audio_proc_limiter_mon__a 126
++#define ma_audio_proc_limiter_mon__len 4
++#define ma_audio_proc_limiter_mon__mask 0xf0
++#define ma_audio_proc_limiter_mon__shift 0x04
++#define ma_audio_proc_limiter_mon__reset 0x00
++//-------------------------------------------------------audio_proc_clip_mon---
++// b3-b0: channel 3-0 clipping monitor
++#define ma_audio_proc_clip_mon__a 126
++#define ma_audio_proc_clip_mon__len 4
++#define ma_audio_proc_clip_mon__mask 0x0f
++#define ma_audio_proc_clip_mon__shift 0x00
++#define ma_audio_proc_clip_mon__reset 0x00
++#endif
++
++#define SOC_ENUM_ERR(xname, xenum)\
++{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
++ .access = SNDRV_CTL_ELEM_ACCESS_READ,\
++ .info = snd_soc_info_enum_double,\
++ .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double,\
++ .private_value = (unsigned long)&(xenum) }
++
++static struct i2c_client *i2c;
++
++struct ma120x0p_priv {
++ struct regmap *regmap;
++ int mclk_div;
++ struct snd_soc_component *component;
++ struct gpio_desc *enable_gpio;
++ struct gpio_desc *mute_gpio;
++ struct gpio_desc *booster_gpio;
++ struct gpio_desc *error_gpio;
++};
++
++static struct ma120x0p_priv *priv_data;
++
++//Used to share the IRQ number within this file
++static unsigned int irqNumber;
++
++// Function prototype for the custom IRQ handler function
++static irqreturn_t ma120x0p_irq_handler(int irq, void *data);
++
++//Alsa Controls
++static const char * const limenable_text[] = {"Bypassed", "Enabled"};
++static const char * const limatack_text[] = {"Slow", "Normal", "Fast"};
++static const char * const limrelease_text[] = {"Slow", "Normal", "Fast"};
++
++static const char * const err_flycap_text[] = {"Ok", "Error"};
++static const char * const err_overcurr_text[] = {"Ok", "Error"};
++static const char * const err_pllerr_text[] = {"Ok", "Error"};
++static const char * const err_pvddunder_text[] = {"Ok", "Error"};
++static const char * const err_overtempw_text[] = {"Ok", "Error"};
++static const char * const err_overtempe_text[] = {"Ok", "Error"};
++static const char * const err_pinlowimp_text[] = {"Ok", "Error"};
++static const char * const err_dcprot_text[] = {"Ok", "Error"};
++
++static const char * const pwr_mode_prof_text[] = {"PMF0", "PMF1", "PMF2",
++"PMF3", "PMF4"};
++
++static const struct soc_enum lim_enable_ctrl =
++ SOC_ENUM_SINGLE(ma_audio_proc_limiterenable__a,
++ ma_audio_proc_limiterenable__shift,
++ ma_audio_proc_limiterenable__len + 1,
++ limenable_text);
++static const struct soc_enum limatack_ctrl =
++ SOC_ENUM_SINGLE(ma_audio_proc_attack__a,
++ ma_audio_proc_attack__shift,
++ ma_audio_proc_attack__len + 1,
++ limatack_text);
++static const struct soc_enum limrelease_ctrl =
++ SOC_ENUM_SINGLE(ma_audio_proc_release__a,
++ ma_audio_proc_release__shift,
++ ma_audio_proc_release__len + 1,
++ limrelease_text);
++static const struct soc_enum err_flycap_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 0, 3, err_flycap_text);
++static const struct soc_enum err_overcurr_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 1, 3, err_overcurr_text);
++static const struct soc_enum err_pllerr_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 2, 3, err_pllerr_text);
++static const struct soc_enum err_pvddunder_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 3, 3, err_pvddunder_text);
++static const struct soc_enum err_overtempw_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 4, 3, err_overtempw_text);
++static const struct soc_enum err_overtempe_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 5, 3, err_overtempe_text);
++static const struct soc_enum err_pinlowimp_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 6, 3, err_pinlowimp_text);
++static const struct soc_enum err_dcprot_ctrl =
++ SOC_ENUM_SINGLE(ma_error__a, 7, 3, err_dcprot_text);
++static const struct soc_enum pwr_mode_prof_ctrl =
++ SOC_ENUM_SINGLE(ma_pmprofile__a, ma_pmprofile__shift, 5,
++ pwr_mode_prof_text);
++
++static const char * const pwr_mode_texts[] = {
++ "Dynamic power mode",
++ "Power mode 1",
++ "Power mode 2",
++ "Power mode 3",
++ };
++
++static const int pwr_mode_values[] = {
++ 0x10,
++ 0x50,
++ 0x60,
++ 0x70,
++ };
++
++static const SOC_VALUE_ENUM_SINGLE_DECL(pwr_mode_ctrl,
++ ma_pm_man__a, 0, 0x70,
++ pwr_mode_texts,
++ pwr_mode_values);
++
++static const DECLARE_TLV_DB_SCALE(ma120x0p_vol_tlv, -5000, 100, 0);
++static const DECLARE_TLV_DB_SCALE(ma120x0p_lim_tlv, -5000, 100, 0);
++static const DECLARE_TLV_DB_SCALE(ma120x0p_lr_tlv, -5000, 100, 0);
++
++static const struct snd_kcontrol_new ma120x0p_snd_controls[] = {
++ //Master Volume
++ SOC_SINGLE_RANGE_TLV("A.Mstr Vol Volume",
++ ma_vol_db_master__a, 0, 0x18, 0x4a, 1, ma120x0p_vol_tlv),
++
++ //L-R Volume ch0
++ SOC_SINGLE_RANGE_TLV("B.L Vol Volume",
++ ma_vol_db_ch0__a, 0, 0x18, 0x4a, 1, ma120x0p_lr_tlv),
++ SOC_SINGLE_RANGE_TLV("C.R Vol Volume",
++ ma_vol_db_ch1__a, 0, 0x18, 0x4a, 1, ma120x0p_lr_tlv),
++
++ //L-R Limiter Threshold ch0-ch1
++ SOC_DOUBLE_R_RANGE_TLV("D.Lim thresh Volume",
++ ma_thr_db_ch0__a, ma_thr_db_ch1__a, 0, 0x0e, 0x4a, 1,
++ ma120x0p_lim_tlv),
++
++ //Enum Switches/Selectors
++ //SOC_ENUM("E.AudioProc Mute", audioproc_mute_ctrl),
++ SOC_ENUM("F.Limiter Enable", lim_enable_ctrl),
++ SOC_ENUM("G.Limiter Attck", limatack_ctrl),
++ SOC_ENUM("H.Limiter Rls", limrelease_ctrl),
++
++ //Enum Error Monitor (read-only)
++ SOC_ENUM_ERR("I.Err flycap", err_flycap_ctrl),
++ SOC_ENUM_ERR("J.Err overcurr", err_overcurr_ctrl),
++ SOC_ENUM_ERR("K.Err pllerr", err_pllerr_ctrl),
++ SOC_ENUM_ERR("L.Err pvddunder", err_pvddunder_ctrl),
++ SOC_ENUM_ERR("M.Err overtempw", err_overtempw_ctrl),
++ SOC_ENUM_ERR("N.Err overtempe", err_overtempe_ctrl),
++ SOC_ENUM_ERR("O.Err pinlowimp", err_pinlowimp_ctrl),
++ SOC_ENUM_ERR("P.Err dcprot", err_dcprot_ctrl),
++
++ //Power modes profiles
++ SOC_ENUM("Q.PM Prof", pwr_mode_prof_ctrl),
++
++ // Power mode selection (Dynamic,1,2,3)
++ SOC_ENUM("R.Power Mode", pwr_mode_ctrl),
++};
++
++//Machine Driver
++static int ma120x0p_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
++{
++ u16 blen = 0x00;
++
++ struct snd_soc_component *component = dai->component;
++
++ priv_data->component = component;
++
++ switch (params_format(params)) {
++ case SNDRV_PCM_FORMAT_S16_LE:
++ blen = 0x10;
++ break;
++ case SNDRV_PCM_FORMAT_S24_LE:
++ blen = 0x00;
++ break;
++ case SNDRV_PCM_FORMAT_S32_LE:
++ blen = 0x00;
++ break;
++ default:
++ dev_err(dai->dev, "Unsupported word length: %u\n",
++ params_format(params));
++ return -EINVAL;
++ }
++
++ // set word length
++ snd_soc_component_update_bits(component, ma_i2s_framesize__a,
++ ma_i2s_framesize__mask, blen);
++
++ return 0;
++}
++
++static int ma120x0p_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
++{
++ int val = 0;
++
++ struct ma120x0p_priv *ma120x0p;
++
++ struct snd_soc_component *component = dai->component;
++
++ ma120x0p = snd_soc_component_get_drvdata(component);
++
++ if (mute)
++ val = 0;
++ else
++ val = 1;
++
++ gpiod_set_value_cansleep(priv_data->mute_gpio, val);
++
++ return 0;
++}
++
++static const struct snd_soc_dai_ops ma120x0p_dai_ops = {
++ .hw_params = ma120x0p_hw_params,
++ .mute_stream = ma120x0p_mute_stream,
++};
++
++static struct snd_soc_dai_driver ma120x0p_dai = {
++ .name = "ma120x0p-amp",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SNDRV_PCM_RATE_CONTINUOUS,
++ .rate_min = 44100,
++ .rate_max = 48000,
++ .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE
++ },
++ .ops = &ma120x0p_dai_ops,
++};
++
++//Codec Driver
++static int ma120x0p_clear_err(struct snd_soc_component *component)
++{
++ int ret = 0;
++
++ struct ma120x0p_priv *ma120x0p;
++
++ ma120x0p = snd_soc_component_get_drvdata(component);
++
++ ret = snd_soc_component_update_bits(component,
++ ma_eh_clear__a, ma_eh_clear__mask, 0x00);
++ if (ret < 0)
++ return ret;
++
++ ret = snd_soc_component_update_bits(component,
++ ma_eh_clear__a, ma_eh_clear__mask, 0x04);
++ if (ret < 0)
++ return ret;
++
++ ret = snd_soc_component_update_bits(component,
++ ma_eh_clear__a, ma_eh_clear__mask, 0x00);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static void ma120x0p_remove(struct snd_soc_component *component)
++{
++ struct ma120x0p_priv *ma120x0p;
++
++ ma120x0p = snd_soc_component_get_drvdata(component);
++}
++
++static int ma120x0p_probe(struct snd_soc_component *component)
++{
++ struct ma120x0p_priv *ma120x0p;
++
++ int ret = 0;
++
++ i2c = container_of(component->dev, struct i2c_client, dev);
++
++ ma120x0p = snd_soc_component_get_drvdata(component);
++
++ //Reset error
++ ma120x0p_clear_err(component);
++ if (ret < 0)
++ return ret;
++
++ // set serial audio format I2S and enable audio processor
++ ret = snd_soc_component_write(component, ma_i2s_format__a, 0x08);
++ if (ret < 0)
++ return ret;
++
++ // Enable audio limiter
++ ret = snd_soc_component_update_bits(component,
++ ma_audio_proc_limiterenable__a,
++ ma_audio_proc_limiterenable__mask, 0x40);
++ if (ret < 0)
++ return ret;
++
++ // Set lim attack to fast
++ ret = snd_soc_component_update_bits(component,
++ ma_audio_proc_attack__a, ma_audio_proc_attack__mask, 0x80);
++ if (ret < 0)
++ return ret;
++
++ // Set lim attack to low
++ ret = snd_soc_component_update_bits(component,
++ ma_audio_proc_release__a, ma_audio_proc_release__mask, 0x00);
++ if (ret < 0)
++ return ret;
++
++ // set volume to 0dB
++ ret = snd_soc_component_write(component, ma_vol_db_master__a, 0x18);
++ if (ret < 0)
++ return ret;
++
++ // set ch0 lim thresh to -15dB
++ ret = snd_soc_component_write(component, ma_thr_db_ch0__a, 0x27);
++ if (ret < 0)
++ return ret;
++
++ // set ch1 lim thresh to -15dB
++ ret = snd_soc_component_write(component, ma_thr_db_ch1__a, 0x27);
++ if (ret < 0)
++ return ret;
++
++ //Check for errors
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x00, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x01, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x02, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x08, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x10, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x20, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x40, 0);
++ if (ret < 0)
++ return ret;
++ ret = snd_soc_component_test_bits(component, ma_error_acc__a, 0x80, 0);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++
++static int ma120x0p_set_bias_level(struct snd_soc_component *component,
++ enum snd_soc_bias_level level)
++{
++ int ret = 0;
++
++ struct ma120x0p_priv *ma120x0p;
++
++ ma120x0p = snd_soc_component_get_drvdata(component);
++
++ switch (level) {
++ case SND_SOC_BIAS_ON:
++ break;
++
++ case SND_SOC_BIAS_PREPARE:
++ break;
++
++ case SND_SOC_BIAS_STANDBY:
++ ret = gpiod_get_value_cansleep(priv_data->enable_gpio);
++ if (ret != 0) {
++ dev_err(component->dev, "Device ma120x0p disabled in STANDBY BIAS: %d\n",
++ ret);
++ return ret;
++ }
++ break;
++
++ case SND_SOC_BIAS_OFF:
++ break;
++ }
++
++ return 0;
++}
++
++static const struct snd_soc_dapm_widget ma120x0p_dapm_widgets[] = {
++ SND_SOC_DAPM_OUTPUT("OUT_A"),
++ SND_SOC_DAPM_OUTPUT("OUT_B"),
++};
++
++static const struct snd_soc_dapm_route ma120x0p_dapm_routes[] = {
++ { "OUT_B", NULL, "Playback" },
++ { "OUT_A", NULL, "Playback" },
++};
++
++static const struct snd_soc_component_driver ma120x0p_component_driver = {
++ .probe = ma120x0p_probe,
++ .remove = ma120x0p_remove,
++ .set_bias_level = ma120x0p_set_bias_level,
++ .dapm_widgets = ma120x0p_dapm_widgets,
++ .num_dapm_widgets = ARRAY_SIZE(ma120x0p_dapm_widgets),
++ .dapm_routes = ma120x0p_dapm_routes,
++ .num_dapm_routes = ARRAY_SIZE(ma120x0p_dapm_routes),
++ .controls = ma120x0p_snd_controls,
++ .num_controls = ARRAY_SIZE(ma120x0p_snd_controls),
++ .use_pmdown_time = 1,
++ .endianness = 1,
++ .non_legacy_dai_naming = 1,
++};
++
++//I2C Driver
++static const struct reg_default ma120x0p_reg_defaults[] = {
++ { 0x01, 0x3c },
++};
++
++static bool ma120x0p_reg_volatile(struct device *dev, unsigned int reg)
++{
++ switch (reg) {
++ case ma_error__a:
++ return true;
++ default:
++ return false;
++ }
++}
++
++static const struct of_device_id ma120x0p_of_match[] = {
++ { .compatible = "ma,ma120x0p", },
++ { }
++};
++
++MODULE_DEVICE_TABLE(of, ma120x0p_of_match);
++
++static struct regmap_config ma120x0p_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++
++ .max_register = 255,
++ .volatile_reg = ma120x0p_reg_volatile,
++
++ .cache_type = REGCACHE_RBTREE,
++ .reg_defaults = ma120x0p_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(ma120x0p_reg_defaults),
++};
++
++static int ma120x0p_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ int ret;
++
++ priv_data = devm_kzalloc(&i2c->dev, sizeof(*priv_data), GFP_KERNEL);
++ if (!priv_data)
++ return -ENOMEM;
++ i2c_set_clientdata(i2c, priv_data);
++
++ priv_data->regmap = devm_regmap_init_i2c(i2c, &ma120x0p_regmap_config);
++ if (IS_ERR(priv_data->regmap)) {
++ ret = PTR_ERR(priv_data->regmap);
++ return ret;
++ }
++
++ //Startup sequence
++
++ //Make sure the device is muted
++ priv_data->mute_gpio = devm_gpiod_get(&i2c->dev, "mute_gp",
++ GPIOD_OUT_LOW);
++ if (IS_ERR(priv_data->mute_gpio)) {
++ ret = PTR_ERR(priv_data->mute_gpio);
++ dev_err(&i2c->dev, "Failed to get mute gpio line: %d\n", ret);
++ return ret;
++ }
++ msleep(50);
++
++// MA120xx0P devices are usually powered by an integrated boost converter.
++// An option GPIO control line is provided to enable the booster properly and
++// in sync with the enable and mute GPIO lines.
++ priv_data->booster_gpio = devm_gpiod_get_optional(&i2c->dev,
++ "booster_gp", GPIOD_OUT_LOW);
++ if (IS_ERR(priv_data->booster_gpio)) {
++ ret = PTR_ERR(priv_data->booster_gpio);
++ dev_err(&i2c->dev,
++ "Failed to get booster enable gpio line: %d\n", ret);
++ return ret;
++ }
++ msleep(50);
++
++ //Enable booster and wait 200ms until stable PVDD
++ gpiod_set_value_cansleep(priv_data->booster_gpio, 1);
++ msleep(200);
++
++ //Enable ma120x0pp
++ priv_data->enable_gpio = devm_gpiod_get(&i2c->dev,
++ "enable_gp", GPIOD_OUT_LOW);
++ if (IS_ERR(priv_data->enable_gpio)) {
++ ret = PTR_ERR(priv_data->enable_gpio);
++ dev_err(&i2c->dev,
++ "Failed to get ma120x0p enable gpio line: %d\n", ret);
++ return ret;
++ }
++ msleep(50);
++
++ //Optional use of ma120x0pp error line as an interrupt trigger to
++ //platform GPIO.
++ //Get error input gpio ma120x0p
++ priv_data->error_gpio = devm_gpiod_get_optional(&i2c->dev,
++ "error_gp", GPIOD_IN);
++ if (IS_ERR(priv_data->error_gpio)) {
++ ret = PTR_ERR(priv_data->error_gpio);
++ dev_err(&i2c->dev,
++ "Failed to get ma120x0p error gpio line: %d\n", ret);
++ return ret;
++ }
++
++ if (priv_data->error_gpio != NULL) {
++ irqNumber = gpiod_to_irq(priv_data->error_gpio);
++
++ ret = devm_request_threaded_irq(&i2c->dev,
++ irqNumber, ma120x0p_irq_handler,
++ NULL, IRQF_TRIGGER_FALLING,
++ "ma120x0p", priv_data);
++ if (ret != 0)
++ dev_warn(&i2c->dev, "Failed to request IRQ: %d\n",
++ ret);
++ }
++
++ ret = devm_snd_soc_register_component(&i2c->dev,
++ &ma120x0p_component_driver, &ma120x0p_dai, 1);
++
++ return ret;
++}
++
++static irqreturn_t ma120x0p_irq_handler(int irq, void *data)
++{
++ gpiod_set_value_cansleep(priv_data->mute_gpio, 0);
++ gpiod_set_value_cansleep(priv_data->enable_gpio, 1);
++ return IRQ_HANDLED;
++}
++
++static int ma120x0p_i2c_remove(struct i2c_client *i2c)
++{
++ snd_soc_unregister_component(&i2c->dev);
++ i2c_set_clientdata(i2c, NULL);
++
++ gpiod_set_value_cansleep(priv_data->mute_gpio, 0);
++ msleep(30);
++ gpiod_set_value_cansleep(priv_data->enable_gpio, 1);
++ msleep(200);
++ gpiod_set_value_cansleep(priv_data->booster_gpio, 0);
++ msleep(200);
++
++ kfree(priv_data);
++
++ return 0;
++}
++
++static void ma120x0p_i2c_shutdown(struct i2c_client *i2c)
++{
++ snd_soc_unregister_component(&i2c->dev);
++ i2c_set_clientdata(i2c, NULL);
++
++ gpiod_set_value_cansleep(priv_data->mute_gpio, 0);
++ msleep(30);
++ gpiod_set_value_cansleep(priv_data->enable_gpio, 1);
++ msleep(200);
++ gpiod_set_value_cansleep(priv_data->booster_gpio, 0);
++ msleep(200);
++
++ kfree(priv_data);
++}
++
++static const struct i2c_device_id ma120x0p_i2c_id[] = {
++ { "ma120x0p", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, ma120x0p_i2c_id);
++
++static struct i2c_driver ma120x0p_i2c_driver = {
++ .driver = {
++ .name = "ma120x0p",
++ .owner = THIS_MODULE,
++ .of_match_table = ma120x0p_of_match,
++ },
++ .probe = ma120x0p_i2c_probe,
++ .remove = ma120x0p_i2c_remove,
++ .shutdown = ma120x0p_i2c_shutdown,
++ .id_table = ma120x0p_i2c_id
++};
++
++static int __init ma120x0p_modinit(void)
++{
++ int ret = 0;
++
++ ret = i2c_add_driver(&ma120x0p_i2c_driver);
++ if (ret != 0) {
++ pr_err("Failed to register MA120X0P I2C driver: %d\n", ret);
++ return ret;
++ }
++ return ret;
++}
++module_init(ma120x0p_modinit);
++
++static void __exit ma120x0p_exit(void)
++{
++ i2c_del_driver(&ma120x0p_i2c_driver);
++}
++module_exit(ma120x0p_exit);
++
++MODULE_AUTHOR("Ariel Muszkat ariel.muszkat@gmail.com>");
++MODULE_DESCRIPTION("ASoC driver for ma120x0p");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/bcm27xx/patches-5.4/950-0477-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch b/target/linux/bcm27xx/patches-5.4/950-0477-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch
new file mode 100644
index 0000000000..f549e73fd3
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0477-ARM-dts-bcm2711-Add-32-bit-PMU-compatibility.patch
@@ -0,0 +1,27 @@
+From e25d9a93812847b4ddc9e883d0cd45b32f8e2f76 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 17 Mar 2020 16:39:07 +0000
+Subject: [PATCH] ARM: dts: bcm2711: Add 32-bit PMU compatibility
+
+The "arm" architecture has no support for the cortex-a72 as such, but
+the performance and measurement unit from the cortex-a15 seems to be
+compatible.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2711-rpi.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi
+@@ -12,6 +12,10 @@
+ sd_poll_once = <&emmc2>, "non-removable?";
+ };
+
++ arm-pmu {
++ compatible = "arm,cortex-a72-pmu", "arm,cortex-a15-pmu";
++ };
++
+ v3dbus {
+ compatible = "simple-bus";
+ #address-cells = <1>;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0478-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch b/target/linux/bcm27xx/patches-5.4/950-0478-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch
new file mode 100644
index 0000000000..9504bb3982
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0478-ARM-dts-bcm271x-Use-a53-pmu-drop-RPI364.patch
@@ -0,0 +1,67 @@
+From 70b0d5d07426e1b9c34ddd6ab4ee99b8c2fb81a6 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Thu, 19 Mar 2020 10:04:46 +0000
+Subject: [PATCH] ARM: dts: bcm271x: Use a53 pmu, drop RPI364
+
+The upstream bcm2837.dtsi uses cortex-a53-pmu, so we can do the same
+but with a fallback to the cortex-a7-pmu which is supported by the
+32-bit kernel.
+
+Now that we're using the natural fallback mechanism of compatible
+strings, the RPI364 macro no longer serves any purpose - remove it.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/bcm2710.dtsi | 6 +-----
+ arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts | 2 --
+ arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts | 2 --
+ arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts | 2 --
+ arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts | 2 --
+ arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts | 2 --
+ 6 files changed, 1 insertion(+), 15 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2710.dtsi
++++ b/arch/arm/boot/dts/bcm2710.dtsi
+@@ -5,11 +5,7 @@
+ compatible = "brcm,bcm2837", "brcm,bcm2836";
+
+ arm-pmu {
+-#ifdef RPI364
+- compatible = "arm,armv8-pmuv3", "arm,cortex-a7-pmu";
+-#else
+- compatible = "arm,cortex-a7-pmu";
+-#endif
++ compatible = "arm,cortex-a53-pmu", "arm,cortex-a7-pmu";
+ };
+
+ soc {
+--- a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-2-b.dts
+@@ -1,3 +1 @@
+-#define RPI364
+-
+ #include "../../../../arm/boot/dts/bcm2710-rpi-2-b.dts"
+--- a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dts
+@@ -1,3 +1 @@
+-#define RPI364
+-
+ #include "../../../../arm/boot/dts/bcm2710-rpi-3-b-plus.dts"
+--- a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dts
+@@ -1,3 +1 @@
+-#define RPI364
+-
+ #include "../../../../arm/boot/dts/bcm2710-rpi-3-b.dts"
+--- a/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2710-rpi-cm3.dts
+@@ -1,3 +1 @@
+-#define RPI364
+-
+ #include "../../../../arm/boot/dts/bcm2710-rpi-cm3.dts"
+--- a/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
++++ b/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
+@@ -1,3 +1 @@
+-#define RPI364
+-
+ #include "../../../../arm/boot/dts/bcm2711-rpi-4-b.dts"
diff --git a/target/linux/bcm27xx/patches-5.4/950-0479-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch b/target/linux/bcm27xx/patches-5.4/950-0479-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch
new file mode 100644
index 0000000000..9d8090441a
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0479-net-bcmgenet-Clear-ID_MODE_DIS-in-EXT_RGMII_OOB_CTRL.patch
@@ -0,0 +1,32 @@
+From cff8c5c2a95a4afd65bfa3198258d03bc790cddb Mon Sep 17 00:00:00 2001
+From: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Date: Tue, 25 Feb 2020 14:11:59 +0100
+Subject: [PATCH] net: bcmgenet: Clear ID_MODE_DIS in
+ EXT_RGMII_OOB_CTRL when not needed
+
+commit 402482a6a78e5c61d8a2ec6311fc5b4aca392cd6 upstream.
+
+Outdated Raspberry Pi 4 firmware might configure the external PHY as
+rgmii although the kernel currently sets it as rgmii-rxid. This makes
+connections unreliable as ID_MODE_DIS is left enabled. To avoid this,
+explicitly clear that bit whenever we don't need it.
+
+Fixes: da38802211cc ("net: bcmgenet: Add RGMII_RXID support")
+Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
+Acked-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Matthias Reichl <hias@horus.com>
+---
+ drivers/net/ethernet/broadcom/genet/bcmmii.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
+@@ -292,6 +292,7 @@ int bcmgenet_mii_config(struct net_devic
+ */
+ if (priv->ext_phy) {
+ reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
++ reg &= ~ID_MODE_DIS;
+ reg |= id_mode_dis;
+ if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
+ reg |= RGMII_MODE_EN_V123;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch b/target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch
new file mode 100644
index 0000000000..1617a45d52
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0480-drm-modes-parse_cmdline-Fix-possible-reference-past-.patch
@@ -0,0 +1,141 @@
+From fade8b3cf37785297b4f8a9bbd13ab107208af5a Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:22 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Fix possible reference past
+ end of string
+
+Commit 8582e244e5fe72d2e9ace186fa8f3ed3bb4122e1 upstream.
+
+Before this commit, if the last option of a video=... option is for
+example "rotate" without a "=<value>" after it then delim will point to
+the terminating 0 of the string, and value which is sets to <delim + 1>
+will point one position past the end of the string.
+
+This commit fixes this by enforcing that the contents of delim equals '='
+as it should be for options which take a value, this check is done in a
+new drm_mode_parse_cmdline_int helper function which factors out the
+common integer parsing code for all the options which take an int.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-1-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 68 ++++++++++++++++---------------------
+ 1 file changed, 30 insertions(+), 38 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1568,11 +1568,34 @@ static int drm_mode_parse_cmdline_res_mo
+ return 0;
+ }
+
++static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
++{
++ const char *value;
++ char *endp;
++
++ /*
++ * delim must point to the '=', otherwise it is a syntax error and
++ * if delim points to the terminating zero, then delim + 1 wil point
++ * past the end of the string.
++ */
++ if (*delim != '=')
++ return -EINVAL;
++
++ value = delim + 1;
++ *int_ret = simple_strtol(value, &endp, 10);
++
++ /* Make sure we have parsed something */
++ if (endp == value)
++ return -EINVAL;
++
++ return 0;
++}
++
+ static int drm_mode_parse_cmdline_options(char *str, size_t len,
+ const struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+ {
+- unsigned int rotation = 0;
++ unsigned int deg, margin, rotation = 0;
+ char *sep = str;
+
+ while ((sep = strchr(sep, ','))) {
+@@ -1588,13 +1611,7 @@ static int drm_mode_parse_cmdline_option
+ }
+
+ if (!strncmp(option, "rotate", delim - option)) {
+- const char *value = delim + 1;
+- unsigned int deg;
+-
+- deg = simple_strtol(value, &sep, 10);
+-
+- /* Make sure we have parsed something */
+- if (sep == value)
++ if (drm_mode_parse_cmdline_int(delim, &deg))
+ return -EINVAL;
+
+ switch (deg) {
+@@ -1619,57 +1636,32 @@ static int drm_mode_parse_cmdline_option
+ }
+ } else if (!strncmp(option, "reflect_x", delim - option)) {
+ rotation |= DRM_MODE_REFLECT_X;
+- sep = delim;
+ } else if (!strncmp(option, "reflect_y", delim - option)) {
+ rotation |= DRM_MODE_REFLECT_Y;
+- sep = delim;
+ } else if (!strncmp(option, "margin_right", delim - option)) {
+- const char *value = delim + 1;
+- unsigned int margin;
+-
+- margin = simple_strtol(value, &sep, 10);
+-
+- /* Make sure we have parsed something */
+- if (sep == value)
++ if (drm_mode_parse_cmdline_int(delim, &margin))
+ return -EINVAL;
+
+ mode->tv_margins.right = margin;
+ } else if (!strncmp(option, "margin_left", delim - option)) {
+- const char *value = delim + 1;
+- unsigned int margin;
+-
+- margin = simple_strtol(value, &sep, 10);
+-
+- /* Make sure we have parsed something */
+- if (sep == value)
++ if (drm_mode_parse_cmdline_int(delim, &margin))
+ return -EINVAL;
+
+ mode->tv_margins.left = margin;
+ } else if (!strncmp(option, "margin_top", delim - option)) {
+- const char *value = delim + 1;
+- unsigned int margin;
+-
+- margin = simple_strtol(value, &sep, 10);
+-
+- /* Make sure we have parsed something */
+- if (sep == value)
++ if (drm_mode_parse_cmdline_int(delim, &margin))
+ return -EINVAL;
+
+ mode->tv_margins.top = margin;
+ } else if (!strncmp(option, "margin_bottom", delim - option)) {
+- const char *value = delim + 1;
+- unsigned int margin;
+-
+- margin = simple_strtol(value, &sep, 10);
+-
+- /* Make sure we have parsed something */
+- if (sep == value)
++ if (drm_mode_parse_cmdline_int(delim, &margin))
+ return -EINVAL;
+
+ mode->tv_margins.bottom = margin;
+ } else {
+ return -EINVAL;
+ }
++ sep = delim;
+ }
+
+ mode->rotation_reflection = rotation;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch b/target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch
new file mode 100644
index 0000000000..ef8c161f52
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0481-drm-modes-parse_cmdline-Make-various-char-pointers-c.patch
@@ -0,0 +1,50 @@
+From 250363a413cd08e723789e1b8821608ff5eebfe6 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:23 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Make various char pointers
+ const
+
+Commit 83e14ea3a64f00897cc31974d3ae4e27e5a7405b upstream.
+
+We are not supposed to modify the passed in string, make char pointers
+used in drm_mode_parse_cmdline_options() const char * where possible.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-2-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1591,15 +1591,15 @@ static int drm_mode_parse_cmdline_int(co
+ return 0;
+ }
+
+-static int drm_mode_parse_cmdline_options(char *str, size_t len,
++static int drm_mode_parse_cmdline_options(const char *str, size_t len,
+ const struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+ {
+ unsigned int deg, margin, rotation = 0;
+- char *sep = str;
++ const char *sep = str;
+
+ while ((sep = strchr(sep, ','))) {
+- char *delim, *option;
++ const char *delim, *option;
+
+ option = sep + 1;
+ delim = strchr(option, '=');
+@@ -1718,8 +1718,8 @@ bool drm_mode_parse_command_line_for_con
+ bool named_mode = false, parse_extras = false;
+ unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
+ unsigned int mode_end = 0;
+- char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+- char *options_ptr = NULL;
++ const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
++ const char *options_ptr = NULL;
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+ int ret;
+
diff --git a/target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch b/target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch
new file mode 100644
index 0000000000..1128ac0c36
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0482-drm-modes-parse_cmdline-Stop-parsing-extras-after-bp.patch
@@ -0,0 +1,95 @@
+From 0e7c5e80d8d310a881d723a426762e8822d5bf35 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:24 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Stop parsing extras after
+ bpp / refresh at ', '
+
+Commit c2ed3e941901810ad3d55ce1935fa22c5007fee4 upstream.
+
+Before this commit it was impossible to add an extra mode argument after
+a bpp or refresh specifier, combined with an option, e.g.
+video=HDMI-1:720x480-24e,rotate=180 would not work, either the "e" to
+force enable would need to be dropped or the ",rotate=180", otherwise
+the mode_option would not be accepted.
+
+This commit fixes this by fixing the length calculation if extras_ptr
+is set to stop the extra parsing at the start of the options (stop at the
+',' options_ptr points to).
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-3-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 10 ++++---
+ .../gpu/drm/selftests/drm_cmdline_selftests.h | 1 +
+ .../drm/selftests/test-drm_cmdline_parser.c | 26 +++++++++++++++++++
+ 3 files changed, 33 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1721,7 +1721,7 @@ bool drm_mode_parse_command_line_for_con
+ const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+ const char *options_ptr = NULL;
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+- int ret;
++ int i, len, ret;
+
+ #ifdef CONFIG_FB
+ if (!mode_option)
+@@ -1841,9 +1841,11 @@ bool drm_mode_parse_command_line_for_con
+ else if (refresh_ptr)
+ extra_ptr = refresh_end_ptr;
+
+- if (extra_ptr &&
+- extra_ptr != options_ptr) {
+- int len = strlen(name) - (extra_ptr - name);
++ if (extra_ptr) {
++ if (options_ptr)
++ len = options_ptr - extra_ptr;
++ else
++ len = strlen(extra_ptr);
+
+ ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
+ connector, mode);
+--- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
++++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+@@ -60,3 +60,4 @@ cmdline_test(drm_cmdline_test_vmirror)
+ cmdline_test(drm_cmdline_test_margin_options)
+ cmdline_test(drm_cmdline_test_multiple_options)
+ cmdline_test(drm_cmdline_test_invalid_option)
++cmdline_test(drm_cmdline_test_bpp_extra_and_option)
+--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
++++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+@@ -992,6 +992,32 @@ static int drm_cmdline_test_invalid_opti
+ return 0;
+ }
+
++static int drm_cmdline_test_bpp_extra_and_option(void *ignored)
++{
++ struct drm_cmdline_mode mode = { };
++
++ FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24e,rotate=180",
++ &no_connector,
++ &mode));
++ FAIL_ON(!mode.specified);
++ FAIL_ON(mode.xres != 720);
++ FAIL_ON(mode.yres != 480);
++ FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
++
++ FAIL_ON(mode.refresh_specified);
++
++ FAIL_ON(!mode.bpp_specified);
++ FAIL_ON(mode.bpp != 24);
++
++ FAIL_ON(mode.rb);
++ FAIL_ON(mode.cvt);
++ FAIL_ON(mode.interlace);
++ FAIL_ON(mode.margins);
++ FAIL_ON(mode.force != DRM_FORCE_ON);
++
++ return 0;
++}
++
+ #include "drm_selftest.c"
+
+ static int __init test_drm_cmdline_init(void)
diff --git a/target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Accept-extras-directly-after.patch b/target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Accept-extras-directly-after.patch
new file mode 100644
index 0000000000..79cfa56e84
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0483-drm-modes-parse_cmdline-Accept-extras-directly-after.patch
@@ -0,0 +1,77 @@
+From bc4d8c5519c74b9bdf4d35369ba76bac01be8ca2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:25 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Accept extras directly
+ after mode combined with options
+
+Commit cfb0881b8f621b656a9e23b31944a5db94cf5842 upstream.
+
+Before this commit it was impossible to combine an extra mode argument
+specified directly after the resolution with an option, e.g.
+video=HDMI-1:720x480e,rotate=180 would not work, either the "e" to force
+enable would need to be dropped or the ",rotate=180", otherwise the
+mode_option would not be accepted.
+
+This commit fixes this by setting parse_extras to true in this case, so
+that drm_mode_parse_cmdline_res_mode() parses the extra arguments directly
+after the resolution.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-4-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 1 +
+ .../gpu/drm/selftests/drm_cmdline_selftests.h | 1 +
+ .../drm/selftests/test-drm_cmdline_parser.c | 24 +++++++++++++++++++
+ 3 files changed, 26 insertions(+)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1794,6 +1794,7 @@ bool drm_mode_parse_command_line_for_con
+ mode_end = refresh_off;
+ } else if (options_ptr) {
+ mode_end = options_off;
++ parse_extras = true;
+ } else {
+ mode_end = strlen(name);
+ parse_extras = true;
+--- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
++++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+@@ -61,3 +61,4 @@ cmdline_test(drm_cmdline_test_margin_opt
+ cmdline_test(drm_cmdline_test_multiple_options)
+ cmdline_test(drm_cmdline_test_invalid_option)
+ cmdline_test(drm_cmdline_test_bpp_extra_and_option)
++cmdline_test(drm_cmdline_test_extra_and_option)
+--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
++++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+@@ -1018,6 +1018,30 @@ static int drm_cmdline_test_bpp_extra_an
+ return 0;
+ }
+
++static int drm_cmdline_test_extra_and_option(void *ignored)
++{
++ struct drm_cmdline_mode mode = { };
++
++ FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480e,rotate=180",
++ &no_connector,
++ &mode));
++ FAIL_ON(!mode.specified);
++ FAIL_ON(mode.xres != 720);
++ FAIL_ON(mode.yres != 480);
++ FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
++
++ FAIL_ON(mode.refresh_specified);
++ FAIL_ON(mode.bpp_specified);
++
++ FAIL_ON(mode.rb);
++ FAIL_ON(mode.cvt);
++ FAIL_ON(mode.interlace);
++ FAIL_ON(mode.margins);
++ FAIL_ON(mode.force != DRM_FORCE_ON);
++
++ return 0;
++}
++
+ #include "drm_selftest.c"
+
+ static int __init test_drm_cmdline_init(void)
diff --git a/target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch b/target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch
new file mode 100644
index 0000000000..0cf2939a06
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0484-drm-modes-parse_cmdline-Rework-drm_mode_parse_cmdlin.patch
@@ -0,0 +1,76 @@
+From 5b6257773b43e7a7b28f86359d2e9ebe15346b78 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:26 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Rework
+ drm_mode_parse_cmdline_options()
+
+Commit 739b200c2edcaaa7a86f37b0c11db57956433dfb upstream.
+
+Refactor drm_mode_parse_cmdline_options() so that it takes a pointer
+to the first option, rather then a pointer to the ',' before the first
+option.
+
+This is a preparation patch for allowing parsing of stand-alone options
+without a mode before them, e.g.: video=HDMI-1:margin_right=14,...
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-5-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 21 +++++++++------------
+ 1 file changed, 9 insertions(+), 12 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1591,23 +1591,21 @@ static int drm_mode_parse_cmdline_int(co
+ return 0;
+ }
+
+-static int drm_mode_parse_cmdline_options(const char *str, size_t len,
++static int drm_mode_parse_cmdline_options(const char *str,
+ const struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+ {
+ unsigned int deg, margin, rotation = 0;
+- const char *sep = str;
++ const char *delim, *option, *sep;
+
+- while ((sep = strchr(sep, ','))) {
+- const char *delim, *option;
+-
+- option = sep + 1;
++ option = str;
++ do {
+ delim = strchr(option, '=');
+ if (!delim) {
+ delim = strchr(option, ',');
+
+ if (!delim)
+- delim = str + len;
++ delim = option + strlen(option);
+ }
+
+ if (!strncmp(option, "rotate", delim - option)) {
+@@ -1661,8 +1659,9 @@ static int drm_mode_parse_cmdline_option
+ } else {
+ return -EINVAL;
+ }
+- sep = delim;
+- }
++ sep = strchr(delim, ',');
++ option = sep + 1;
++ } while (sep);
+
+ mode->rotation_reflection = rotation;
+
+@@ -1855,9 +1854,7 @@ bool drm_mode_parse_command_line_for_con
+ }
+
+ if (options_ptr) {
+- int len = strlen(name) - (options_ptr - name);
+-
+- ret = drm_mode_parse_cmdline_options(options_ptr, len,
++ ret = drm_mode_parse_cmdline_options(options_ptr + 1,
+ connector, mode);
+ if (ret)
+ return false;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch b/target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch
new file mode 100644
index 0000000000..ac37b72f74
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0485-drm-modes-parse_cmdline-Add-freestanding-argument-to.patch
@@ -0,0 +1,49 @@
+From d3c76025a7de614fade5ffcaa8c1d88d8d64213e Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:27 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Add freestanding argument
+ to drm_mode_parse_cmdline_options()
+
+Commit 99e2716e053734b70434502867be24d20a3e2d84 upstream.
+
+Add a freestanding function argument to drm_mode_parse_cmdline_options()
+similar to how drm_mode_parse_cmdline_extra() already has this.
+
+This is a preparation patch for allowing parsing of stand-alone options
+without a mode before them, e.g.: video=HDMI-1:margin_right=14,...
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-6-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1592,6 +1592,7 @@ static int drm_mode_parse_cmdline_int(co
+ }
+
+ static int drm_mode_parse_cmdline_options(const char *str,
++ bool freestanding,
+ const struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+ {
+@@ -1663,6 +1664,9 @@ static int drm_mode_parse_cmdline_option
+ option = sep + 1;
+ } while (sep);
+
++ if (rotation && freestanding)
++ return -EINVAL;
++
+ mode->rotation_reflection = rotation;
+
+ return 0;
+@@ -1855,6 +1859,7 @@ bool drm_mode_parse_command_line_for_con
+
+ if (options_ptr) {
+ ret = drm_mode_parse_cmdline_options(options_ptr + 1,
++ false,
+ connector, mode);
+ if (ret)
+ return false;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch b/target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch
new file mode 100644
index 0000000000..7f0c6299de
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0486-drm-modes-parse_cmdline-Set-bpp-refresh_specified-af.patch
@@ -0,0 +1,64 @@
+From 5b7efd2fa0c75164373d6faf28fec4b89065d39c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:28 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Set bpp/refresh_specified
+ after successful parsing
+
+Commit 6a2d163756545aa3180d7851d5f8322b865e72be upstream.
+
+drm_connector_get_cmdline_mode() calls
+drm_mode_parse_command_line_for_connector() with &connector->cmdline_mode
+as mode argument, so anything which we store in the mode arguments gets
+kept even if we return false.
+
+Avoid storing a possibly false-postive bpp/refresh_specified setting
+in connector->cmdline_mode by moving the setting of these to after
+successful parsing of the bpp/refresh parts of the video= argument.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-7-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1771,10 +1771,8 @@ bool drm_mode_parse_command_line_for_con
+
+ /* Try to locate the bpp and refresh specifiers, if any */
+ bpp_ptr = strchr(name, '-');
+- if (bpp_ptr) {
++ if (bpp_ptr)
+ bpp_off = bpp_ptr - name;
+- mode->bpp_specified = true;
+- }
+
+ refresh_ptr = strchr(name, '@');
+ if (refresh_ptr) {
+@@ -1782,7 +1780,6 @@ bool drm_mode_parse_command_line_for_con
+ return false;
+
+ refresh_off = refresh_ptr - name;
+- mode->refresh_specified = true;
+ }
+
+ /* Locate the start of named options */
+@@ -1825,6 +1822,8 @@ bool drm_mode_parse_command_line_for_con
+ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
+ if (ret)
+ return false;
++
++ mode->bpp_specified = true;
+ }
+
+ if (refresh_ptr) {
+@@ -1832,6 +1831,8 @@ bool drm_mode_parse_command_line_for_con
+ &refresh_end_ptr, mode);
+ if (ret)
+ return false;
++
++ mode->refresh_specified = true;
+ }
+
+ /*
diff --git a/target/linux/bcm27xx/patches-5.4/950-0487-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch b/target/linux/bcm27xx/patches-5.4/950-0487-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch
new file mode 100644
index 0000000000..301ad57f03
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0487-drm-modes-parse_cmdline-Allow-specifying-stand-alone.patch
@@ -0,0 +1,247 @@
+From b3212eba63b541206e12c8dc31fc0d99d916b210 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:29 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Allow specifying
+ stand-alone options
+
+Commit 7b1cce760afe38b40f0989cdf10b2190dccf9815 upstream.
+
+Some options which can be specified on the commandline, such as
+margin_right=..., margin_left=..., etc. are applied not only to the
+specified mode, but to all modes. As such it would be nice if the user
+can simply say e.g.
+video=HDMI-1:margin_right=14,margin_left=24,margin_bottom=36,margin_top=42
+
+This commit refactors drm_mode_parse_command_line_for_connector() to
+add support for this, and as a nice side effect also cleans up the
+function a bit.
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-8-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 92 +++++++------------
+ .../gpu/drm/selftests/drm_cmdline_selftests.h | 2 +
+ .../drm/selftests/test-drm_cmdline_parser.c | 50 ++++++++++
+ 3 files changed, 86 insertions(+), 58 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1677,17 +1677,6 @@ static const char * const drm_named_mode
+ "PAL",
+ };
+
+-static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size)
+-{
+- int i;
+-
+- for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++)
+- if (!strncmp(mode, drm_named_modes_whitelist[i], size))
+- return true;
+-
+- return false;
+-}
+-
+ /**
+ * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
+ * @mode_option: optional per connector mode option
+@@ -1718,7 +1707,7 @@ bool drm_mode_parse_command_line_for_con
+ struct drm_cmdline_mode *mode)
+ {
+ const char *name;
+- bool named_mode = false, parse_extras = false;
++ bool freestanding = false, parse_extras = false;
+ unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
+ unsigned int mode_end = 0;
+ const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+@@ -1738,49 +1727,14 @@ bool drm_mode_parse_command_line_for_con
+
+ name = mode_option;
+
+- /*
+- * This is a bit convoluted. To differentiate between the
+- * named modes and poorly formatted resolutions, we need a
+- * bunch of things:
+- * - We need to make sure that the first character (which
+- * would be our resolution in X) is a digit.
+- * - If not, then it's either a named mode or a force on/off.
+- * To distinguish between the two, we need to run the
+- * extra parsing function, and if not, then we consider it
+- * a named mode.
+- *
+- * If this isn't enough, we should add more heuristics here,
+- * and matching unit-tests.
+- */
+- if (!isdigit(name[0]) && name[0] != 'x') {
+- unsigned int namelen = strlen(name);
+-
+- /*
+- * Only the force on/off options can be in that case,
+- * and they all take a single character.
+- */
+- if (namelen == 1) {
+- ret = drm_mode_parse_cmdline_extra(name, namelen, true,
+- connector, mode);
+- if (!ret)
+- return true;
+- }
+-
+- named_mode = true;
+- }
+-
+ /* Try to locate the bpp and refresh specifiers, if any */
+ bpp_ptr = strchr(name, '-');
+ if (bpp_ptr)
+ bpp_off = bpp_ptr - name;
+
+ refresh_ptr = strchr(name, '@');
+- if (refresh_ptr) {
+- if (named_mode)
+- return false;
+-
++ if (refresh_ptr)
+ refresh_off = refresh_ptr - name;
+- }
+
+ /* Locate the start of named options */
+ options_ptr = strchr(name, ',');
+@@ -1800,23 +1754,45 @@ bool drm_mode_parse_command_line_for_con
+ parse_extras = true;
+ }
+
+- if (named_mode) {
+- if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
+- return false;
+-
+- if (!drm_named_mode_is_in_whitelist(name, mode_end))
+- return false;
++ /* First check for a named mode */
++ for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
++ ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
++ if (ret == mode_end) {
++ if (refresh_ptr)
++ return false; /* named + refresh is invalid */
++
++ strcpy(mode->name, drm_named_modes_whitelist[i]);
++ mode->specified = true;
++ break;
++ }
++ }
+
+- strscpy(mode->name, name, mode_end + 1);
+- } else {
++ /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
++ if (!mode->specified && isdigit(name[0])) {
+ ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+ parse_extras,
+ connector,
+ mode);
+ if (ret)
+ return false;
++
++ mode->specified = true;
++ }
++
++ /* No mode? Check for freestanding extras and/or options */
++ if (!mode->specified) {
++ unsigned int len = strlen(mode_option);
++
++ if (bpp_ptr || refresh_ptr)
++ return false; /* syntax error */
++
++ if (len == 1 || (len >= 2 && mode_option[1] == ','))
++ extra_ptr = mode_option;
++ else
++ options_ptr = mode_option - 1;
++
++ freestanding = true;
+ }
+- mode->specified = true;
+
+ if (bpp_ptr) {
+ ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
+@@ -1852,7 +1828,7 @@ bool drm_mode_parse_command_line_for_con
+ else
+ len = strlen(extra_ptr);
+
+- ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
++ ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
+ connector, mode);
+ if (ret)
+ return false;
+@@ -1860,7 +1836,7 @@ bool drm_mode_parse_command_line_for_con
+
+ if (options_ptr) {
+ ret = drm_mode_parse_cmdline_options(options_ptr + 1,
+- false,
++ freestanding,
+ connector, mode);
+ if (ret)
+ return false;
+--- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
++++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+@@ -62,3 +62,5 @@ cmdline_test(drm_cmdline_test_multiple_o
+ cmdline_test(drm_cmdline_test_invalid_option)
+ cmdline_test(drm_cmdline_test_bpp_extra_and_option)
+ cmdline_test(drm_cmdline_test_extra_and_option)
++cmdline_test(drm_cmdline_test_freestanding_options)
++cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
+--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
++++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+@@ -1042,6 +1042,56 @@ static int drm_cmdline_test_extra_and_op
+ return 0;
+ }
+
++static int drm_cmdline_test_freestanding_options(void *ignored)
++{
++ struct drm_cmdline_mode mode = { };
++
++ FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
++ &no_connector,
++ &mode));
++ FAIL_ON(mode.specified);
++ FAIL_ON(mode.refresh_specified);
++ FAIL_ON(mode.bpp_specified);
++
++ FAIL_ON(mode.tv_margins.right != 14);
++ FAIL_ON(mode.tv_margins.left != 24);
++ FAIL_ON(mode.tv_margins.bottom != 36);
++ FAIL_ON(mode.tv_margins.top != 42);
++
++ FAIL_ON(mode.rb);
++ FAIL_ON(mode.cvt);
++ FAIL_ON(mode.interlace);
++ FAIL_ON(mode.margins);
++ FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
++
++ return 0;
++}
++
++static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored)
++{
++ struct drm_cmdline_mode mode = { };
++
++ FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
++ &no_connector,
++ &mode));
++ FAIL_ON(mode.specified);
++ FAIL_ON(mode.refresh_specified);
++ FAIL_ON(mode.bpp_specified);
++
++ FAIL_ON(mode.tv_margins.right != 14);
++ FAIL_ON(mode.tv_margins.left != 24);
++ FAIL_ON(mode.tv_margins.bottom != 36);
++ FAIL_ON(mode.tv_margins.top != 42);
++
++ FAIL_ON(mode.rb);
++ FAIL_ON(mode.cvt);
++ FAIL_ON(mode.interlace);
++ FAIL_ON(mode.margins);
++ FAIL_ON(mode.force != DRM_FORCE_ON);
++
++ return 0;
++}
++
+ #include "drm_selftest.c"
+
+ static int __init test_drm_cmdline_init(void)
diff --git a/target/linux/bcm27xx/patches-5.4/950-0488-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch b/target/linux/bcm27xx/patches-5.4/950-0488-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch
new file mode 100644
index 0000000000..29382003a8
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0488-drm-modes-parse_cmdline-Add-support-for-specifying-p.patch
@@ -0,0 +1,157 @@
+From 7d395633947fa6595a117f40e0f27ba87be77d6c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:30 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Add support for specifying
+ panel_orientation (v2)
+
+Commit 4e7a4a6fbdc669c44e6079f9d5eb25673749455f upstream.
+
+Sometimes we want to override a connector's panel_orientation from the
+kernel commandline. Either for testing and for special cases, e.g. a kiosk
+like setup which uses a TV mounted in portrait mode.
+
+Users can already specify a "rotate" option through a video= kernel cmdline
+option. But that only supports 0/180 degrees (see drm_client_modeset TODO)
+and only works for in kernel modeset clients, not for userspace kms users.
+
+The "panel-orientation" connector property OTOH does support 90/270 degrees
+as it leaves dealing with the rotation up to userspace and this does work
+for userspace kms clients (at least those which support this property).
+
+Changes in v2:
+-Add missing ':' after @panel_orientation (reported by kbuild test robot)
+
+BugLink: https://gitlab.freedesktop.org/plymouth/plymouth/merge_requests/83
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-9-hdegoede@redhat.com
+---
+ Documentation/fb/modedb.rst | 3 ++
+ drivers/gpu/drm/drm_modes.c | 32 +++++++++++++++++++
+ .../gpu/drm/selftests/drm_cmdline_selftests.h | 1 +
+ .../drm/selftests/test-drm_cmdline_parser.c | 22 +++++++++++++
+ include/drm/drm_connector.h | 8 +++++
+ 5 files changed, 66 insertions(+)
+
+--- a/Documentation/fb/modedb.rst
++++ b/Documentation/fb/modedb.rst
+@@ -65,6 +65,9 @@ Valid options are::
+ - reflect_y (boolean): Perform an axial symmetry on the Y axis
+ - rotate (integer): Rotate the initial framebuffer by x
+ degrees. Valid values are 0, 90, 180 and 270.
++ - panel_orientation, one of "normal", "upside_down", "left_side_up", or
++ "right_side_up". For KMS drivers only, this sets the "panel orientation"
++ property on the kms connector as hint for kms users.
+
+
+ -----------------------------------------------------------------------------
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1591,6 +1591,33 @@ static int drm_mode_parse_cmdline_int(co
+ return 0;
+ }
+
++static int drm_mode_parse_panel_orientation(const char *delim,
++ struct drm_cmdline_mode *mode)
++{
++ const char *value;
++
++ if (*delim != '=')
++ return -EINVAL;
++
++ value = delim + 1;
++ delim = strchr(value, ',');
++ if (!delim)
++ delim = value + strlen(value);
++
++ if (!strncmp(value, "normal", delim - value))
++ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
++ else if (!strncmp(value, "upside_down", delim - value))
++ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
++ else if (!strncmp(value, "left_side_up", delim - value))
++ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
++ else if (!strncmp(value, "right_side_up", delim - value))
++ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
++ else
++ return -EINVAL;
++
++ return 0;
++}
++
+ static int drm_mode_parse_cmdline_options(const char *str,
+ bool freestanding,
+ const struct drm_connector *connector,
+@@ -1657,6 +1684,9 @@ static int drm_mode_parse_cmdline_option
+ return -EINVAL;
+
+ mode->tv_margins.bottom = margin;
++ } else if (!strncmp(option, "panel_orientation", delim - option)) {
++ if (drm_mode_parse_panel_orientation(delim, mode))
++ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+@@ -1715,6 +1745,8 @@ bool drm_mode_parse_command_line_for_con
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+ int i, len, ret;
+
++ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
++
+ #ifdef CONFIG_FB
+ if (!mode_option)
+ mode_option = fb_mode_option;
+--- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
++++ b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+@@ -64,3 +64,4 @@ cmdline_test(drm_cmdline_test_bpp_extra_
+ cmdline_test(drm_cmdline_test_extra_and_option)
+ cmdline_test(drm_cmdline_test_freestanding_options)
+ cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
++cmdline_test(drm_cmdline_test_panel_orientation)
+--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
++++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+@@ -1092,6 +1092,28 @@ static int drm_cmdline_test_freestanding
+ return 0;
+ }
+
++static int drm_cmdline_test_panel_orientation(void *ignored)
++{
++ struct drm_cmdline_mode mode = { };
++
++ FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down",
++ &no_connector,
++ &mode));
++ FAIL_ON(mode.specified);
++ FAIL_ON(mode.refresh_specified);
++ FAIL_ON(mode.bpp_specified);
++
++ FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
++
++ FAIL_ON(mode.rb);
++ FAIL_ON(mode.cvt);
++ FAIL_ON(mode.interlace);
++ FAIL_ON(mode.margins);
++ FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
++
++ return 0;
++}
++
+ #include "drm_selftest.c"
+
+ static int __init test_drm_cmdline_init(void)
+--- a/include/drm/drm_connector.h
++++ b/include/drm/drm_connector.h
+@@ -1066,6 +1066,14 @@ struct drm_cmdline_mode {
+ unsigned int rotation_reflection;
+
+ /**
++ * @panel_orientation:
++ *
++ * drm-connector "panel orientation" property override value,
++ * DRM_MODE_PANEL_ORIENTATION_UNKNOWN if not set.
++ */
++ enum drm_panel_orientation panel_orientation;
++
++ /**
+ * @tv_margins: TV margins to apply to the mode.
+ */
+ struct drm_connector_tv_margins tv_margins;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0489-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch b/target/linux/bcm27xx/patches-5.4/950-0489-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch
new file mode 100644
index 0000000000..ce80f19b74
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0489-drm-modes-parse_cmdline-Remove-some-unnecessary-code.patch
@@ -0,0 +1,38 @@
+From 339666068713986cfe1456175dd8a7514f6ed2ab Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:31 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Remove some unnecessary
+ code (v2)
+
+Commit 5b926617cdef41ce0696e09834991194b1759e28 upstream.
+
+fb_get_options() will return fb_mode_option if no video=<connector-name>
+argument is present on the kernel commandline, so there is no need to also
+do this in drm_mode_parse_command_line_for_connector() as our only caller
+uses fb_get_options() to get the mode_option argument.
+
+Changes in v2:
+-Split out the changes dealing with the initialization of the mode struct
+ into a separate patch
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-10-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1747,11 +1747,6 @@ bool drm_mode_parse_command_line_for_con
+
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+
+-#ifdef CONFIG_FB
+- if (!mode_option)
+- mode_option = fb_mode_option;
+-#endif
+-
+ if (!mode_option) {
+ mode->specified = false;
+ return false;
diff --git a/target/linux/bcm27xx/patches-5.4/950-0490-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch b/target/linux/bcm27xx/patches-5.4/950-0490-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch
new file mode 100644
index 0000000000..6c17d894f7
--- /dev/null
+++ b/target/linux/bcm27xx/patches-5.4/950-0490-drm-modes-parse_cmdline-Explicitly-memset-the-passed.patch
@@ -0,0 +1,41 @@
+From d89b3f22cf7b6bba8081f6d16c9087019fdcf586 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 18 Nov 2019 16:51:32 +0100
+Subject: [PATCH] drm/modes: parse_cmdline: Explicitly memset the
+ passed in drm_cmdline_mode struct
+
+Commit d1fe276b5115f0d581c3cfe6154633b3547e8aab upstream.
+
+Instead of only setting mode->specified on false on an early exit and
+leaving e.g. mode->bpp_specified and mode->refresh_specified as is,
+lets be consistent and just zero out the entire passed in struct at
+the top of drm_mode_parse_command_line_for_connector()
+
+Changes in v3:
+-Drop "mode->specified = false;" line instead of the "return false;" (oops)
+ This crasher was reported-by: kernel test robot <lkp@intel.com>
+
+Acked-by: Maxime Ripard <mripard@kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20191118155134.30468-11-hdegoede@redhat.com
+---
+ drivers/gpu/drm/drm_modes.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/drm_modes.c
++++ b/drivers/gpu/drm/drm_modes.c
+@@ -1745,12 +1745,11 @@ bool drm_mode_parse_command_line_for_con
+ char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+ int i, len, ret;
+
++ memset(mode, 0, sizeof(*mode));
+ mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
+
+- if (!mode_option) {
+- mode->specified = false;
++ if (!mode_option)
+ return false;
+- }
+
+ name = mode_option;
+