From: Álvaro Fernández Rojas Date: Mon, 23 Mar 2020 07:48:08 +0000 (+0100) Subject: bcm27xx: sync 5.4 patches with RPi Foundation X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=6c9b5d6972aa84b85aa9d5d95b3e01f23525e929;p=openwrt%2Fstaging%2Flinusw.git bcm27xx: sync 5.4 patches with RPi Foundation Signed-off-by: Álvaro Fernández Rojas --- 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 +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 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 +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 +--- + 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 +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 +--- + 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: ++ ++ + 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 ++#include ++ ++ ++/ { ++ 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 + * ++ * merus-amp.c ++ * by Ariel Muszkat ++ * Jorgen Kragh Jakobsen ++ * + * 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 ++ * Jorgen Kragh Jakobsen ++ * ++ * Copyright (C) 2019 Infineon Technologies AG ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 +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 +--- + 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 +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 +--- + 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 +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 +Acked-by: Florian Fainelli +Signed-off-by: David S. Miller +Signed-off-by: Matthias Reichl +--- + 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 +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 "=" after it then delim will point to +the terminating 0 of the string, and value which is sets to +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 +Signed-off-by: Hans de Goede +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, °)) + 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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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 +Signed-off-by: Hans de Goede +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 +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= +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 +Signed-off-by: Hans de Goede +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 +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 + +Acked-by: Maxime Ripard +Signed-off-by: Hans de Goede +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; +