Merge pull request #4976 from jernejsk/aw-patch-rework

Allwinner: Complete patch reorganization
This commit is contained in:
dhewg 2021-01-17 10:35:45 +01:00 committed by GitHub
commit 7b30b3d505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 5413 additions and 5339 deletions

View File

@ -0,0 +1,53 @@
From ff9ed48eb584e583e20509af6cde1ba80ebd3edd Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 16 Jan 2021 10:49:00 +0100
Subject: [PATCH] HACK: a64: Add HDMI sound card
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -161,6 +161,24 @@
};
};
+ sound_hdmi: sound_hdmi {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s2>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+ };
+
timer {
compatible = "arm,armv8-timer";
allwinner,erratum-unknown1;
@@ -878,7 +896,6 @@
resets = <&ccu RST_BUS_I2S2>;
dma-names = "rx", "tx";
dmas = <&dma 27>, <&dma 27>;
- status = "disabled";
};
dai: dai@1c22c00 {
@@ -1178,6 +1195,7 @@
};
hdmi: hdmi@1ee0000 {
+ #sound-dai-cells = <0>;
compatible = "allwinner,sun50i-a64-dw-hdmi",
"allwinner,sun8i-a83t-dw-hdmi";
reg = <0x01ee0000 0x10000>;

View File

@ -8,11 +8,9 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 31143fe64d91..1f22b0f6a4e0 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -1055,6 +1055,9 @@ mali: gpu@1c40000 {
@@ -1101,6 +1101,9 @@
clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>;
clock-names = "bus", "core";
resets = <&ccu RST_BUS_GPU>;
@ -22,6 +20,3 @@ index 31143fe64d91..1f22b0f6a4e0 100644
};
gic: interrupt-controller@1c81000 {
--
2.26.0

View File

@ -1,48 +0,0 @@
Date: Sun, 3 Dec 2017 11:43:08 -0800
Subject: [PATCH] Add A64 HDMI sound node
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 29 +++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 0f69f35939755..0b44018361cbf 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -727,6 +727,36 @@
status = "disabled";
};
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 27>;
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "tx";
+ allwinner,playback-channels = <8>;
+ };
+
+ sound_hdmi: sound_hdmi {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s2>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+ };
+
rtc: rtc@1f00000 {
compatible = "allwinner,sun6i-a31-rtc";
reg = <0x01f00000 0x54>;

View File

@ -1,11 +0,0 @@
diff -Nur a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi 2018-11-17 18:26:20.000000000 +0100
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi 2018-11-17 19:29:15.132911602 +0100
@@ -892,6 +892,7 @@
};
hdmi: hdmi@1ee0000 {
+ #sound-dai-cells = <0>;
compatible = "allwinner,sun50i-a64-dw-hdmi",
"allwinner,sun8i-a83t-dw-hdmi";
reg = <0x01ee0000 0x10000>;

View File

@ -1,24 +0,0 @@
From 08d35c5d5ce6de3453f17e6eff7375afa74173d2 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Thu, 2 Jan 2020 19:09:25 +0100
Subject: [PATCH] Add frame inversion to correct multi-channel audio
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 988e261a0ab3..4e20a0872c0c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -1101,6 +1101,7 @@
simple-audio-card,format = "i2s";
simple-audio-card,name = "allwinner-hdmi";
simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
simple-audio-card,codec {
sound-dai = <&hdmi>;
--
2.24.1

View File

@ -0,0 +1,26 @@
From 4cc652f2c660bd01bd0d8cefde272400cbe82fbe Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 16 Jan 2021 11:32:04 +0100
Subject: [PATCH 1/2] ARM: dts: sun8i: h2-plus: bananapi-m2-zero: Increase BT
UART speed
Bluetooth module on BananaPi M2 Zero can also be used for streaming
audio. However, for that case higher UART speed is required.
Add a max-speed property.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
+++ b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
@@ -125,6 +125,7 @@
bluetooth {
compatible = "brcm,bcm43438-bt";
+ max-speed = <1500000>;
clocks = <&rtc 1>;
clock-names = "lpo";
vbat-supply = <&reg_vcc3v3>;

View File

@ -1,14 +1,13 @@
commit 9702424ea23471e3bdbe6a150e28a1ecdf837d2c
Author: PJBrs <pjbrs@floorenpj.xs4all.nl>
Date: Fri Feb 21 08:56:04 2020 +0100
From aa47c3b292cb0ffcf2c00b2a12c477ec3027a729 Mon Sep 17 00:00:00 2001
From: PJBrs <pjbrs@floorenpj.xs4all.nl>
Date: Sat, 16 Jan 2021 11:39:45 +0100
Subject: [PATCH 2/2] ARM: dts: sunxi: h2-plus-bananapi-m2-zero: Add HDMI out
ARM: dts: sunxi: h2-plus-bananapi-m2-zero: Add HDMI out
Add HDMI out, including the display engine, to the BananaPi
M2 Zero.
Add HDMI out, including the display engine, to the BananaPi M2 Zero.
---
.../dts/sun8i-h2-plus-bananapi-m2-zero.dts | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
index 38e8da594e44..9051a1097258 100644
--- a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
+++ b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
@@ -26,6 +26,17 @@
@ -29,7 +28,7 @@ index 38e8da594e44..9051a1097258 100644
leds {
compatible = "gpio-leds";
@@ -140,6 +151,20 @@
@@ -107,6 +118,20 @@
};
};

View File

@ -1,12 +0,0 @@
diff --git a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
index b4ddfaf01b45..e746abb724b4 100644
--- a/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
+++ b/arch/arm/boot/dts/sun8i-h2-plus-bananapi-m2-zero.dts
@@ -125,6 +125,7 @@ &uart1 {
bluetooth {
compatible = "brcm,bcm43438-bt";
+ max-speed = <1500000>;
clocks = <&rtc 1>;
clock-names = "lpo";
vbat-supply = <&reg_vcc3v3>;

View File

@ -1,56 +0,0 @@
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 8aa2befc..d3d70eac 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -53,6 +53,23 @@
#address-cells = <1>;
#size-cells = <1>;
+ sound_hdmi: sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s2>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+ };
+
clocks {
#address-cells = <1>;
#size-cells = <1>;
@@ -631,6 +648,19 @@
status = "disabled";
};
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 27>;
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "tx";
+ allwinner,playback-channels = <8>;
+ };
+
codec: codec@1c22c00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun8i-h3-codec";
@@ -110,6 +126,7 @@
};
hdmi: hdmi@1ee0000 {
+ #sound-dai-cells = <0>;
compatible = "allwinner,sun8i-h3-dw-hdmi",
"allwinner,sun8i-a83t-dw-hdmi";
reg = <0x01ee0000 0x10000>;

View File

@ -1,24 +0,0 @@
From 51dcda7a261bcadca0a8f5e6fe6241ec266438d0 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Thu, 2 Jan 2020 19:03:35 +0100
Subject: [PATCH] Add frame inversion to correct multi-channel audio
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 8644435e66d3..7375a9479e84 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -82,6 +82,7 @@
simple-audio-card,format = "i2s";
simple-audio-card,name = "allwinner-hdmi";
simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
simple-audio-card,codec {
sound-dai = <&hdmi>;
--
2.24.1

View File

@ -1,85 +1,24 @@
From bf21ad0889bdcc1dc12fe5a024fd7df7ad2c4310 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Tue, 26 Feb 2019 20:45:14 +0000
Subject: [PATCH 1/2] WIP: dw-hdmi-cec: sleep 100ms on error
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
index 6c323510f128..b5a1a85c8700 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -7,6 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -132,8 +133,15 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0);
- if (stat & CEC_STAT_ERROR_INIT) {
- cec->tx_status = CEC_TX_STATUS_ERROR;
+ /* Status with both done and error_initiator bits have been seen
+ * on Rockchip RK3328 devices, transmit attempt seems to have failed
+ * when this happens, report as low drive and block cec-framework
+ * 100ms before core retransmits the failed message, this seems to
+ * mitigate the issue with failed transmit attempts.
+ */
+ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) {
+ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat);
+ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
} else if (stat & CEC_STAT_DONE) {
@@ -144,6 +152,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
cec->tx_status = CEC_TX_STATUS_NACK;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
+ } else if (stat & CEC_STAT_ERROR_INIT) {
+ cec->tx_status = CEC_TX_STATUS_ERROR;
+ cec->tx_done = true;
+ ret = IRQ_WAKE_THREAD;
}
if (stat & CEC_STAT_EOM) {
@@ -176,6 +188,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data)
if (cec->tx_done) {
cec->tx_done = false;
+ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE)
+ msleep(100);
cec_transmit_attempt_done(adap, cec->tx_status);
}
if (cec->rx_done) {
--
2.21.0
From 12f1abe2b5cee6575c6dd9cd29b17b589f044b80 Mon Sep 17 00:00:00 2001
From 0981ac8f42983c820790b14668d59f39b0375d90 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 25 May 2019 12:03:39 +0200
Subject: [PATCH 2/2] WIP: sun8i-hdmi CEC improvements
Subject: [PATCH] HACK: SW CEC implementation for H3
Many H3 boards lack 32768 Hz external oscillator, so internal RC is used
instead. However, it's too unstable for CEC. Use SW implementation
instead. That makes it usable, albeit sensitive to cpufreq changes.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 +-
drivers/gpu/drm/sun4i/Kconfig | 10 +++
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 11 +++
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 83 ++++++++++++++++++++++-
drivers/gpu/drm/sun4i/Kconfig | 2 +
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 12 ++++
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 74 ++++++++++++++++++++++-
include/drm/bridge/dw_hdmi.h | 2 +
5 files changed, 105 insertions(+), 3 deletions(-)
5 files changed, 89 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 09fdc9f87651..f359c4c3f1d1 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2713,7 +2713,7 @@ __dw_hdmi_probe(struct platform_device *pdev,
@@ -3421,7 +3421,7 @@ struct dw_hdmi *dw_hdmi_probe(struct pla
hdmi->audio = platform_device_register_full(&pdevinfo);
}
@ -88,32 +27,20 @@ index 09fdc9f87651..f359c4c3f1d1 100644
cec.hdmi = hdmi;
cec.ops = &dw_hdmi_cec_ops;
cec.irq = irq;
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index 1dbbc3a1b763..7149c72e44c8 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -60,6 +60,16 @@ config DRM_SUN8I_DW_HDMI
@@ -56,6 +56,8 @@ config DRM_SUN8I_DW_HDMI
tristate "Support for Allwinner version of DesignWare HDMI"
depends on DRM_SUN4I
select DRM_DW_HDMI
+ select CEC_CORE
+ select CEC_PIN
help
Choose this option if you have an Allwinner SoC with the
DesignWare HDMI controller with custom HDMI PHY. If M is
selected the module will be called sun8i_dw_hdmi.
+config DRM_SUN8I_DW_HDMI_CEC
+ bool "Allwinner DesignWare HDMI CEC Support for 40nm SoCs"
+ depends on DRM_SUN8I_DW_HDMI
+ select CEC_CORE
+ select CEC_PIN
+ help
+ Choose this option if you have an 40nm Allwinner SoC with
+ the DesignWare HDMI controller with custom HDMI PHY and
+ you want to use CEC.
+
config DRM_SUN8I_MIXER
tristate "Support for Allwinner Display Engine 2.0 Mixer"
default MACH_SUN8I
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
index 720c5aa8adc1..49ca001923e3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -12,6 +12,8 @@
@@ -13,6 +13,8 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@ -122,7 +49,7 @@ index 720c5aa8adc1..49ca001923e3 100644
#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
@@ -144,6 +145,13 @@
@@ -145,6 +147,13 @@
#define SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK GENMASK(5, 0)
#define SUN8I_HDMI_PHY_CEC_REG 0x003c
@ -136,7 +63,7 @@ index 720c5aa8adc1..49ca001923e3 100644
struct sun8i_hdmi_phy;
@@ -151,6 +159,7 @@ struct sun8i_hdmi_phy_variant {
@@ -152,6 +161,7 @@ struct sun8i_hdmi_phy_variant {
bool has_phy_clk;
bool has_second_pll;
unsigned int is_custom_phy : 1;
@ -144,7 +71,7 @@ index 720c5aa8adc1..49ca001923e3 100644
const struct dw_hdmi_curr_ctrl *cur_ctr;
const struct dw_hdmi_mpll_config *mpll_cfg;
const struct dw_hdmi_phy_config *phy_cfg;
@@ -163,6 +172,8 @@ struct sun8i_hdmi_phy_variant {
@@ -164,6 +174,8 @@ struct sun8i_hdmi_phy_variant {
};
struct sun8i_hdmi_phy {
@ -153,11 +80,9 @@ index 720c5aa8adc1..49ca001923e3 100644
struct clk *clk_bus;
struct clk *clk_mod;
struct clk *clk_phy;
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 43643ad31730..d840bc07cba6 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -504,8 +504,9 @@ static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
@@ -505,8 +505,9 @@ static void sun8i_hdmi_phy_init_h3(struc
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0);
@ -169,14 +94,13 @@ index 43643ad31730..d840bc07cba6 100644
/* read calibration data */
regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
@@ -531,8 +532,49 @@ void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
@@ -532,8 +533,47 @@ void sun8i_hdmi_phy_set_ops(struct sun8i
plat_data->cur_ctr = variant->cur_ctr;
plat_data->phy_config = variant->phy_cfg;
}
+ plat_data->is_cec_unusable = phy->variant->bit_bang_cec;
}
+#ifdef CONFIG_DRM_SUN8I_DW_HDMI_CEC
+static int sun8i_hdmi_phy_cec_pin_read(struct cec_adapter *adap)
+{
+ struct sun8i_hdmi_phy *phy = cec_get_drvdata(adap);
@ -214,12 +138,11 @@ index 43643ad31730..d840bc07cba6 100644
+ .low = sun8i_hdmi_phy_cec_pin_low,
+ .high = sun8i_hdmi_phy_cec_pin_high,
+};
+#endif
+
static const struct regmap_config sun8i_hdmi_phy_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
@@ -549,6 +591,7 @@ static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
@@ -550,6 +590,7 @@ static const struct sun8i_hdmi_phy_varia
};
static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
@ -227,19 +150,10 @@ index 43643ad31730..d840bc07cba6 100644
.has_phy_clk = true,
.is_custom_phy = true,
.phy_init = &sun8i_hdmi_phy_init_h3,
@@ -566,6 +610,7 @@ static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
};
static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
+ .bit_bang_cec = true,
.has_phy_clk = true,
.is_custom_phy = true,
.phy_init = &sun8i_hdmi_phy_init_h3,
@@ -711,10 +756,38 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
@@ -712,10 +753,36 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw
clk_prepare_enable(phy->clk_phy);
}
+#ifdef CONFIG_DRM_SUN8I_DW_HDMI_CEC
+ if (phy->variant->bit_bang_cec) {
+ phy->cec_adapter =
+ cec_pin_allocate_adapter(&sun8i_hdmi_phy_cec_pin_ops,
@ -259,7 +173,6 @@ index 43643ad31730..d840bc07cba6 100644
+ if (ret < 0)
+ goto err_put_cec_notifier;
+ }
+#endif
+
hdmi->phy = phy;
@ -274,7 +187,7 @@ index 43643ad31730..d840bc07cba6 100644
err_disable_clk_mod:
clk_disable_unprepare(phy->clk_mod);
err_disable_clk_bus:
@@ -739,6 +814,9 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)
@@ -740,6 +807,9 @@ void sun8i_hdmi_phy_remove(struct sun8i_
{
struct sun8i_hdmi_phy *phy = hdmi->phy;
@ -284,19 +197,14 @@ index 43643ad31730..d840bc07cba6 100644
clk_disable_unprepare(phy->clk_mod);
clk_disable_unprepare(phy->clk_bus);
clk_disable_unprepare(phy->clk_phy);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 323febe7f102..cec73761856d 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -144,6 +144,8 @@ struct dw_hdmi_plat_data {
int (*configure_phy)(struct dw_hdmi *hdmi,
const struct dw_hdmi_plat_data *pdata,
@@ -153,6 +153,8 @@ struct dw_hdmi_plat_data {
const struct dw_hdmi_phy_config *phy_config;
int (*configure_phy)(struct dw_hdmi *hdmi, void *data,
unsigned long mpixelclock);
+
+ unsigned int is_cec_unusable : 1;
};
struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
--
2.21.0

View File

@ -0,0 +1,25 @@
From 54b5c2cb4fc87ca72daa662423d4d969f3b5edb8 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 16 Jan 2021 11:49:57 +0100
Subject: [PATCH] ARM: dts: sunxi: bananapi-m2-plus: Increase BT UART speed
Bluetooth module on BananaPi M2 Plus can also be used for streaming
audio. However, for that case higher UART speed is required.
Add a max-speed property.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi | 1 +
1 file changed, 1 insertion(+)
--- a/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
+++ b/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
@@ -219,6 +219,7 @@
bluetooth {
compatible = "brcm,bcm43438-bt";
+ max-speed = <1500000>;
clocks = <&rtc 1>;
clock-names = "lpo";
vbat-supply = <&reg_vcc3v3>;

View File

@ -1,12 +0,0 @@
diff --git a/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi b/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
index 39263e74fbb5..0ec6109ec625 100644
--- a/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
+++ b/arch/arm/boot/dts/sunxi-bananapi-m2-plus.dtsi
@@ -219,6 +219,7 @@
bluetooth {
compatible = "brcm,bcm43438-bt";
+ max-speed = <1500000>;
clocks = <&rtc 1>;
clock-names = "lpo";
vbat-supply = <&reg_vcc3v3>;

View File

@ -1,24 +0,0 @@
From 51dcda7a261bcadca0a8f5e6fe6241ec266438d0 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Thu, 2 Jan 2020 19:03:35 +0100
Subject: [PATCH] Add frame inversion to correct multi-channel audio
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 8644435e66d3..7375a9479e84 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -82,6 +82,7 @@
simple-audio-card,format = "i2s";
simple-audio-card,name = "allwinner-hdmi";
simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
simple-audio-card,codec {
sound-dai = <&hdmi>;
--
2.24.1

View File

@ -1,36 +0,0 @@
#
# Configuration for H3 analog output
#
<confdir:pcm/front.conf>
H3_Audio_Codec.pcm.front.0 {
@args [ CARD ]
@args.CARD {
type string
}
type hooks
slave.pcm {
type hw
card $CARD
}
hooks.0 {
type ctl_elems
hook_args [
{
name "Line Out Playback Volume"
lock true
preserve true
optional false
value 31
}
{
name "Line Out Playback Switch"
lock true
preserve true
optional false
value [ on on ]
}
]
}
}

View File

@ -1,56 +0,0 @@
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 8aa2befc..d3d70eac 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -53,6 +53,23 @@
#address-cells = <1>;
#size-cells = <1>;
+ sound_hdmi: sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s2>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+ };
+
clocks {
#address-cells = <1>;
#size-cells = <1>;
@@ -631,6 +648,19 @@
status = "disabled";
};
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 27>;
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "tx";
+ allwinner,playback-channels = <8>;
+ };
+
codec: codec@1c22c00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun8i-h3-codec";
@@ -110,6 +126,7 @@
};
hdmi: hdmi@1ee0000 {
+ #sound-dai-cells = <0>;
compatible = "allwinner,sun8i-h3-dw-hdmi",
"allwinner,sun8i-a83t-dw-hdmi";
reg = <0x01ee0000 0x10000>;

View File

@ -1,24 +0,0 @@
From 51dcda7a261bcadca0a8f5e6fe6241ec266438d0 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Thu, 2 Jan 2020 19:03:35 +0100
Subject: [PATCH] Add frame inversion to correct multi-channel audio
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 8644435e66d3..7375a9479e84 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -82,6 +82,7 @@
simple-audio-card,format = "i2s";
simple-audio-card,name = "allwinner-hdmi";
simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
simple-audio-card,codec {
sound-dai = <&hdmi>;
--
2.24.1

View File

@ -0,0 +1,53 @@
From da5268aa6c9a552ceebf74263acf997489368adc Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 16 Jan 2021 10:58:14 +0100
Subject: [PATCH 01/14] HACK: h6: Add HDMI sound card
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -108,6 +108,24 @@
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ sound_hdmi: sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -651,7 +669,6 @@
dmas = <&dma 4>, <&dma 4>;
resets = <&ccu RST_BUS_I2S1>;
dma-names = "rx", "tx";
- status = "disabled";
};
spdif: spdif@5093000 {
@@ -784,6 +801,7 @@
};
hdmi: hdmi@6000000 {
+ #sound-dai-cells = <0>;
compatible = "allwinner,sun50i-h6-dw-hdmi";
reg = <0x06000000 0x10000>;
reg-io-width = <1>;

View File

@ -0,0 +1,70 @@
From 7f12904df66e28c2a5fa8ea652ed9eee48a22131 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Wed, 27 Mar 2019 13:21:06 +0100
Subject: [PATCH 02/14] net: stmmac: sun8i: Use devm_regulator_get for PHY
regulator
Use devm_regulator_get instead of devm_regulator_get_optional and rely
on dummy supply. This avoids NULL checks before regulator_enable/disable
calls.
This path also improves error reporting, because we now report both
use of dummy supply and error during registration with more detail,
instead of generic info level message "No regulator found" that
was reported previously on errors and lack of regulator property in DT.
Finally, we'll be adding further optional regulators, and the overall
code will be simpler.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 23 ++++++++-----------
1 file changed, 10 insertions(+), 13 deletions(-)
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -544,12 +544,10 @@ static int sun8i_dwmac_init(struct platf
struct sunxi_priv_data *gmac = priv;
int ret;
- if (gmac->regulator) {
- ret = regulator_enable(gmac->regulator);
- if (ret) {
- dev_err(&pdev->dev, "Fail to enable regulator\n");
- return ret;
- }
+ ret = regulator_enable(gmac->regulator);
+ if (ret) {
+ dev_err(&pdev->dev, "Fail to enable regulator\n");
+ return ret;
}
ret = clk_prepare_enable(gmac->tx_clk);
@@ -1017,8 +1015,7 @@ static void sun8i_dwmac_exit(struct plat
clk_disable_unprepare(gmac->tx_clk);
- if (gmac->regulator)
- regulator_disable(gmac->regulator);
+ regulator_disable(gmac->regulator);
}
static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
@@ -1155,12 +1152,12 @@ static int sun8i_dwmac_probe(struct plat
}
/* Optional regulator for PHY */
- gmac->regulator = devm_regulator_get_optional(dev, "phy");
+ gmac->regulator = devm_regulator_get(dev, "phy");
if (IS_ERR(gmac->regulator)) {
- if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- dev_info(dev, "No regulator found\n");
- gmac->regulator = NULL;
+ ret = PTR_ERR(gmac->regulator);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get PHY regulator (%d)\n", ret);
+ return ret;
}
/* The "GMAC clock control" register might be located in the

View File

@ -0,0 +1,81 @@
From 455e29ad5f37b40532b9cf56781dab3c3eb275b5 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:29:29 +0200
Subject: [PATCH 03/14] net: stmmac: sun8i: Rename PHY regulator variable to
regulator_phy
We'll be adding further optional regulators, and this makes it clearer
what the regulator is for.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 32 ++++++++++---------
1 file changed, 17 insertions(+), 15 deletions(-)
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -57,19 +57,21 @@ struct emac_variant {
};
/* struct sunxi_priv_data - hold all sunxi private data
- * @tx_clk: reference to MAC TX clock
- * @ephy_clk: reference to the optional EPHY clock for the internal PHY
- * @regulator: reference to the optional regulator
- * @rst_ephy: reference to the optional EPHY reset for the internal PHY
- * @variant: reference to the current board variant
- * @regmap: regmap for using the syscon
- * @internal_phy_powered: Does the internal PHY is enabled
- * @mux_handle: Internal pointer used by mdio-mux lib
+ * @tx_clk: reference to MAC TX clock
+ * @ephy_clk: reference to the optional EPHY clock for
+ * the internal PHY
+ * @regulator_phy: reference to the optional regulator
+ * @rst_ephy: reference to the optional EPHY reset for
+ * the internal PHY
+ * @variant: reference to the current board variant
+ * @regmap: regmap for using the syscon
+ * @internal_phy_powered: Does the internal PHY is enabled
+ * @mux_handle: Internal pointer used by mdio-mux lib
*/
struct sunxi_priv_data {
struct clk *tx_clk;
struct clk *ephy_clk;
- struct regulator *regulator;
+ struct regulator *regulator_phy;
struct reset_control *rst_ephy;
const struct emac_variant *variant;
struct regmap_field *regmap_field;
@@ -544,9 +546,9 @@ static int sun8i_dwmac_init(struct platf
struct sunxi_priv_data *gmac = priv;
int ret;
- ret = regulator_enable(gmac->regulator);
+ ret = regulator_enable(gmac->regulator_phy);
if (ret) {
- dev_err(&pdev->dev, "Fail to enable regulator\n");
+ dev_err(&pdev->dev, "Fail to enable PHY regulator\n");
return ret;
}
@@ -1015,7 +1017,7 @@ static void sun8i_dwmac_exit(struct plat
clk_disable_unprepare(gmac->tx_clk);
- regulator_disable(gmac->regulator);
+ regulator_disable(gmac->regulator_phy);
}
static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
@@ -1152,9 +1154,9 @@ static int sun8i_dwmac_probe(struct plat
}
/* Optional regulator for PHY */
- gmac->regulator = devm_regulator_get(dev, "phy");
- if (IS_ERR(gmac->regulator)) {
- ret = PTR_ERR(gmac->regulator);
+ gmac->regulator_phy = devm_regulator_get(dev, "phy");
+ if (IS_ERR(gmac->regulator_phy)) {
+ ret = PTR_ERR(gmac->regulator_phy);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get PHY regulator (%d)\n", ret);
return ret;

View File

@ -0,0 +1,95 @@
From a2903d15de86fc3ab455a665e22ad6e5c27f8c43 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:31:38 +0200
Subject: [PATCH 04/14] net: stmmac: sun8i: Add support for enabling a
regulator for PHY I/O pins
Orange Pi 3 has two regulators that power the Realtek RTL8211E. According
to the phy datasheet, both regulators need to be enabled at the same time.
Add support for the second optional regulator, "phy-io", to the glue
driver.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 30 ++++++++++++++++---
1 file changed, 26 insertions(+), 4 deletions(-)
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -61,6 +61,8 @@ struct emac_variant {
* @ephy_clk: reference to the optional EPHY clock for
* the internal PHY
* @regulator_phy: reference to the optional regulator
+ * @regulator_phy_io: reference to the optional regulator for
+ * PHY I/O pins
* @rst_ephy: reference to the optional EPHY reset for
* the internal PHY
* @variant: reference to the current board variant
@@ -72,6 +74,7 @@ struct sunxi_priv_data {
struct clk *tx_clk;
struct clk *ephy_clk;
struct regulator *regulator_phy;
+ struct regulator *regulator_phy_io;
struct reset_control *rst_ephy;
const struct emac_variant *variant;
struct regmap_field *regmap_field;
@@ -546,21 +549,30 @@ static int sun8i_dwmac_init(struct platf
struct sunxi_priv_data *gmac = priv;
int ret;
+ ret = regulator_enable(gmac->regulator_phy_io);
+ if (ret) {
+ dev_err(&pdev->dev, "Fail to enable PHY I/O regulator\n");
+ return ret;
+ }
+
ret = regulator_enable(gmac->regulator_phy);
if (ret) {
dev_err(&pdev->dev, "Fail to enable PHY regulator\n");
- return ret;
+ goto err_disable_regulator_phy_io;
}
ret = clk_prepare_enable(gmac->tx_clk);
if (ret) {
- if (gmac->regulator)
- regulator_disable(gmac->regulator);
dev_err(&pdev->dev, "Could not enable AHB clock\n");
- return ret;
+ goto err_disable_regulator_phy;
}
return 0;
+err_disable_regulator_phy:
+ regulator_disable(gmac->regulator_phy);
+err_disable_regulator_phy_io:
+ regulator_disable(gmac->regulator_phy_io);
+ return ret;
}
static void sun8i_dwmac_core_init(struct mac_device_info *hw,
@@ -1018,6 +1030,7 @@ static void sun8i_dwmac_exit(struct plat
clk_disable_unprepare(gmac->tx_clk);
regulator_disable(gmac->regulator_phy);
+ regulator_disable(gmac->regulator_phy_io);
}
static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
@@ -1162,6 +1175,15 @@ static int sun8i_dwmac_probe(struct plat
return ret;
}
+ /* Optional regulator for PHY I/O pins */
+ gmac->regulator_phy_io = devm_regulator_get(dev, "phy-io");
+ if (IS_ERR(gmac->regulator_phy_io)) {
+ ret = PTR_ERR(gmac->regulator_phy_io);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get PHY I/O regulator (%d)\n", ret);
+ return ret;
+ }
+
/* The "GMAC clock control" register might be located in the
* CCU address range (on the R40), or the system control address
* range (on most other sun8i and later SoCs).

View File

@ -0,0 +1,100 @@
From 3a078af461185f3ed34c182616365da3a60c6b77 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:54:48 +0200
Subject: [PATCH 05/14] arm64: dts: allwinner: orange-pi-3: Enable ethernet
Orange Pi 3 has two regulators that power the Realtek RTL8211E
PHY. According to the datasheet, both regulators need to be enabled
at the same time, or that "phy-io" should be enabled slightly earlier
than "phy" regulator.
RTL8211E/RTL8211EG datasheet says:
Note 4: 2.5V (or 1.8/1.5V) RGMII power should be risen simultaneously
or slightly earlier than 3.3V power. Rising 2.5V (or 1.8/1.5V) power
later than 3.3V power may lead to errors.
The driver ensures the regulator enable ordering. The timing is set
in DT via startup-delay-us.
We also need to wait at least 30ms after power-up/reset, before
accessing the PHY registers.
All values of RX/TX delay were tested exhaustively and a middle one
of the range of working values was chosen.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../dts/allwinner/sun50i-h6-orangepi-3.dts | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
@@ -15,6 +15,7 @@
aliases {
serial0 = &uart0;
serial1 = &uart1;
+ ethernet0 = &emac;
};
chosen {
@@ -64,6 +65,15 @@
regulator-always-on;
};
+ reg_gmac_2v5: gmac-2v5 {
+ compatible = "regulator-fixed";
+ regulator-name = "gmac-2v5";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ enable-active-high;
+ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
+ };
+
reg_vcc33_wifi: vcc33-wifi {
/* Always on 3.3V regulator for WiFi and BT */
compatible = "regulator-fixed";
@@ -128,6 +138,35 @@
};
};
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_rgmii_pins>;
+ phy-mode = "rgmii-txid";
+ phy-handle = <&ext_rgmii_phy>;
+ /*
+ * The board uses 2.5V RGMII signalling. Power sequence to enable
+ * the phy is to enable GMAC-2V5 and GMAC-3V (aldo2) power rails
+ * at the same time and to wait 100ms. The driver enables phy-io
+ * first. Delay is achieved with enable-ramp-delay on reg_aldo2.
+ */
+ phy-supply = <&reg_aldo2>;
+ phy-io-supply = <&reg_gmac_2v5>;
+ allwinner,rx-delay-ps = <1500>;
+ allwinner,tx-delay-ps = <700>;
+ status = "okay";
+};
+
+&mdio {
+ ext_rgmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+
+ reset-gpios = <&pio 3 14 GPIO_ACTIVE_LOW>; /* PD14 */
+ reset-assert-us = <15000>;
+ reset-deassert-us = <40000>;
+ };
+};
+
&mmc0 {
vmmc-supply = <&reg_cldo1>;
cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
@@ -207,6 +246,7 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-name = "vcc33-audio-tv-ephy-mac";
+ regulator-enable-ramp-delay = <100000>;
};
/* ALDO3 is shorted to CLDO1 */

View File

@ -0,0 +1,67 @@
From e58355ab59c95b3ce708d3fdb417e3893170cfde Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:34:57 +0200
Subject: [PATCH 06/14] net: stmmac: sun8i: Fix reboot issue with ethernet on
Orange Pi 3
We disable both phy regulators before reboot, so that they are in a
known state on the next boot. This should be done in u-boot, but
it doesn't support AXP806 yet, thus this workaround.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -17,6 +17,7 @@
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/stmmac.h>
@@ -80,6 +81,7 @@ struct sunxi_priv_data {
struct regmap_field *regmap_field;
bool internal_phy_powered;
void *mux_handle;
+ struct notifier_block reboot_nb;
};
/* EMAC clock register @ 0x30 in the "system control" address range */
@@ -1130,6 +1132,19 @@ out_put_node:
return regmap;
}
+
+static int sun8i_dwmac_reboot_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct sunxi_priv_data *gmac = container_of(nb, struct sunxi_priv_data,
+ reboot_nb);
+
+ regulator_disable(gmac->regulator_phy);
+ regulator_disable(gmac->regulator_phy_io);
+
+ return NOTIFY_DONE;
+}
+
static int sun8i_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -1184,6 +1199,13 @@ static int sun8i_dwmac_probe(struct plat
return ret;
}
+ gmac->reboot_nb.notifier_call = sun8i_dwmac_reboot_notifier;
+ ret = devm_register_reboot_notifier(dev, &gmac->reboot_nb);
+ if (ret) {
+ dev_err(dev, "Failed to register reboot notifier (%d)\n", ret);
+ return ret;
+ }
+
/* The "GMAC clock control" register might be located in the
* CCU address range (on the R40), or the system control address
* range (on most other sun8i and later SoCs).

View File

@ -1,7 +1,7 @@
From b5554a30a6486e6e769130718d285902e6705bf8 Mon Sep 17 00:00:00 2001
From df7cfa735a251371d3bbee07994fc5e8af55e508 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Mon, 25 Dec 2017 12:10:59 +0800
Subject: [PATCH] arm64: allwinner: dts: h6: enable USB3 port on Pine H64
Subject: [PATCH 07/14] arm64: allwinner: dts: h6: enable USB3 port on Pine H64
Pine H64 board have a USB3 port, which is connected to the USB3 pins of
the H6 SoC, and the 5V power supply is controlled via GPIO (shared with
@ -15,11 +15,9 @@ Reviewed-by: Chen-Yu Tsai <wens@csie.org>
arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
index f01fdf622756f..f2d04cfeec900 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -71,6 +71,10 @@
@@ -97,6 +97,10 @@
status = "okay";
};
@ -30,7 +28,7 @@ index f01fdf622756f..f2d04cfeec900 100644
&emac {
pinctrl-names = "default";
pinctrl-0 = <&ext_rgmii_pins>;
@@ -279,3 +283,8 @@
@@ -331,3 +335,8 @@
usb3_vbus-supply = <&reg_usb_vbus>;
status = "okay";
};

View File

@ -1,18 +1,16 @@
From fa11b2ef7b8359f70d010d3b76b7dfd90250dc5c Mon Sep 17 00:00:00 2001
From 8d6daa429e4b4c97131b16a69cd34ab486b2c248 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 16 Aug 2019 16:40:20 +0200
Subject: [PATCH] arm64: dts: allwinner: h6: Add AC200 EPHY related nodes
Subject: [PATCH 08/14] arm64: dts: allwinner: h6: Add AC200 EPHY related nodes
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 51 ++++++++++++++++++++
1 file changed, 51 insertions(+)
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 56 ++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 8eec8685a50b..5eeb7da7a0ab 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -17,6 +17,16 @@
@@ -16,6 +16,16 @@
#address-cells = <1>;
#size-cells = <1>;
@ -29,7 +27,7 @@ index 8eec8685a50b..5eeb7da7a0ab 100644
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -218,6 +228,10 @@
@@ -319,6 +329,10 @@
cpu_speed_grade: cpu-speed-grade@1c {
reg = <0x1c 0x4>;
};
@ -40,19 +38,33 @@ index 8eec8685a50b..5eeb7da7a0ab 100644
};
watchdog: watchdog@30090a0 {
@@ -268,6 +284,11 @@
@@ -363,6 +377,13 @@
drive-strength = <40>;
};
+ ext_rmii_pins: rmii_pins {
+ pins = "PA0", "PA1", "PA2", "PA3", "PA4",
+ "PA5", "PA6", "PA7", "PA8", "PA9";
+ function = "emac";
+ drive-strength = <40>;
+ };
+
hdmi_pins: hdmi-pins {
pins = "PH8", "PH9", "PH10";
function = "hdmi";
@@ -383,6 +404,11 @@
function = "i2c2";
};
+ i2c3_pins: i2c3-pins {
+ pins = "PB17", "PB18";
+ function = "i2c3";
+ };
+
hdmi_pins: hdmi-pins {
pins = "PH8", "PH9", "PH10";
function = "hdmi";
@@ -290,6 +311,11 @@
mmc0_pins: mmc0-pins {
pins = "PF0", "PF1", "PF2", "PF3",
"PF4", "PF5";
@@ -409,6 +435,11 @@
bias-pull-up;
};
@ -61,11 +73,11 @@ index 8eec8685a50b..5eeb7da7a0ab 100644
+ function = "pwm1";
+ };
+
mmc2_pins: mmc2-pins {
pins = "PC1", "PC4", "PC5", "PC6",
"PC7", "PC8", "PC9", "PC10",
@@ -408,6 +434,31 @@
status = "disabled";
/omit-if-no-ref/
spi0_pins: spi0-pins {
pins = "PC0", "PC2", "PC3";
@@ -639,6 +670,31 @@
#size-cells = <0>;
};
+ i2c3: i2c@5002c00 {
@ -96,6 +108,3 @@ index 8eec8685a50b..5eeb7da7a0ab 100644
emac: ethernet@5020000 {
compatible = "allwinner,sun50i-h6-emac",
"allwinner,sun50i-a64-emac";
--
2.22.1

View File

@ -0,0 +1,55 @@
From b6b784bac19b9ee68b7f7ee5855216b76ac118cd Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 15 Jan 2020 18:39:17 +0100
Subject: [PATCH 09/14] arm64: dts: allwinner: h6: tanix-tx6: enable emmc
Tanix TX6 has 32 GiB eMMC. Add a node for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-tanix-tx6.dts | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
@@ -32,6 +32,13 @@
};
};
+ reg_vcc1v8: vcc1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
reg_vcc3v3: vcc3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc3v3";
@@ -91,6 +98,15 @@
status = "okay";
};
+&mmc2 {
+ vmmc-supply = <&reg_vcc3v3>;
+ vqmmc-supply = <&reg_vcc1v8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ bus-width = <8>;
+ status = "okay";
+};
+
&ohci0 {
status = "okay";
};
@@ -99,6 +115,10 @@
status = "okay";
};
+&pio {
+ vcc-pc-supply = <&reg_vcc1v8>;
+};
+
&r_ir {
linux,rc-map-name = "rc-tanix-tx5max";
status = "okay";

View File

@ -0,0 +1,75 @@
From ff190627e3986569a2516f36e218adcde02fc78b Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 24 Aug 2019 01:03:05 +0200
Subject: [PATCH 10/14] arm64: dts: allwinner: h6: tanix-tx6: enable ethernet
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-tanix-tx6.dts | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
@@ -13,6 +13,7 @@
compatible = "oranth,tanix-tx6", "allwinner,sun50i-h6";
aliases {
+ ethernet0 = &emac;
serial0 = &uart0;
};
@@ -54,6 +55,10 @@
};
};
+&ac200_pwm_clk {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_vdd_cpu_gpu>;
};
@@ -74,6 +79,14 @@
status = "okay";
};
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_rmii_pins>;
+ phy-mode = "rmii";
+ phy-handle = <&ext_rmii_phy>;
+ status = "okay";
+};
+
&gpu {
mali-supply = <&reg_vdd_cpu_gpu>;
status = "okay";
@@ -89,6 +102,17 @@
};
};
+&i2c3 {
+ status = "okay";
+};
+
+&mdio {
+ ext_rmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins>;
@@ -119,6 +143,10 @@
vcc-pc-supply = <&reg_vcc1v8>;
};
+&pwm {
+ status = "okay";
+};
+
&r_ir {
linux,rc-map-name = "rc-tanix-tx5max";
status = "okay";

View File

@ -1,18 +1,16 @@
From e087c727b23ed0665136973e24a0292c14522723 Mon Sep 17 00:00:00 2001
From 483a90d0500c528b2faeed662c3209f779d43103 Mon Sep 17 00:00:00 2001
From: Sebastian Meyer <git-commit@mailhell.seb7.de>
Date: Mon, 3 Feb 2020 21:27:47 +0100
Subject: [PATCH 4/4] arm64: allwinner: h6: Enable USB3 for OrangePi Lite2
Subject: [PATCH 11/14] arm64: allwinner: h6: Enable USB3 for OrangePi Lite2
Signed-off-by: Sebastian Meyer <git-commit@mailhell.seb7.de>
---
.../allwinner/sun50i-h6-orangepi-lite2.dts | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-lite2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-lite2.dts
index e8770858b5d0..6ca46b1cabb9 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-lite2.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-lite2.dts
@@ -11,6 +11,16 @@ aliases {
@@ -11,6 +11,16 @@
serial1 = &uart1; /* BT-UART */
};
@ -29,7 +27,7 @@ index e8770858b5d0..6ca46b1cabb9 100644
wifi_pwrseq: wifi_pwrseq {
compatible = "mmc-pwrseq-simple";
clocks = <&rtc 1>;
@@ -20,6 +30,10 @@ wifi_pwrseq: wifi_pwrseq {
@@ -20,6 +30,10 @@
};
};
@ -40,7 +38,7 @@ index e8770858b5d0..6ca46b1cabb9 100644
&mmc1 {
vmmc-supply = <&reg_cldo2>;
vqmmc-supply = <&reg_bldo3>;
@@ -72,3 +86,8 @@ bluetooth {
@@ -72,3 +86,8 @@
max-speed = <1500000>;
};
};
@ -49,6 +47,3 @@ index e8770858b5d0..6ca46b1cabb9 100644
+ phy-supply = <&reg_usb_vbus>;
+ status = "okay";
+};
--
2.26.0

View File

@ -1,3 +1,12 @@
From 4b723d23c444ae9dc85ecea51a1ae4de092ddf54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez?=
<alejandro.gonzalez.correo@gmail.com>
Date: Sun, 25 Aug 2019 17:05:58 +0200
Subject: [PATCH 12/14] mmc: sunxi: fix unusuable eMMC on some H6 boards by
disabling DDR
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Some Allwinner H6 boards have timing problems when dealing with
DDR-capable eMMC cards. These boards include the Pine H64 and Tanix TX6.
@ -26,11 +35,9 @@ Signed-off-by: Alejandro González <alejandro.gonzalez.correo@gmail.com>
drivers/mmc/host/sunxi-mmc.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index d577a6b0ceae..dac57d76d009 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -1395,14 +1395,17 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
@@ -1398,14 +1398,17 @@ static int sunxi_mmc_probe(struct platfo
/*
* Some H5 devices do not have signal traces precise enough to

View File

@ -0,0 +1,45 @@
From 083e09f834e58cad72671e4df2136cf36c10aaa7 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 29 Oct 2020 21:04:24 +0100
Subject: [PATCH 13/14] pineh64 model b - bluetooth wip
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-pine-h64-model-b.dts | 16 ++++++++++++++++
drivers/bluetooth/hci_h5.c | 3 +++
2 files changed, 19 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
@@ -34,3 +34,19 @@
non-removable;
status = "okay";
};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "realtek,rtl8723bs-bt";
+ device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
+ host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
+ enable-gpios = <&r_pio 1 4 GPIO_ACTIVE_HIGH>; /* PM4 */
+ firmware-postfix = "OBDA8723";
+ max-speed = <1500000>;
+ };
+};
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -820,6 +820,9 @@ static int h5_serdev_probe(struct serdev
if (!data)
return -ENODEV;
+ of_property_read_string(dev->of_node,
+ "firmware-postfix", &h5->id);
+
h5->vnd = (const struct h5_vnd *)data;
}

View File

@ -1,17 +1,15 @@
From 8515bba5b33addcf87c4da5ab67cd7ffc052a87d Mon Sep 17 00:00:00 2001
From 64954a507d442da5c2615897e6d35154c9c2f593 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Tue, 8 Dec 2020 19:48:39 -0600
Subject: [PATCH] hack to fix sun8i_dwmac
Subject: [PATCH 14/14] hack to fix sun8i_dwmac
---
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index d1a47145fe4e0..54f8ee992f560 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -1299,12 +1299,14 @@ static const struct of_device_id sun8i_dwmac_match[] = {
@@ -1310,12 +1310,14 @@ static const struct of_device_id sun8i_d
};
MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);

View File

@ -1,68 +0,0 @@
From 026ec1598d98a0bd45785a44a74ddb7063d2f776 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 22 Jan 2019 20:16:58 +0100
Subject: [PATCH] AW H6 I2S WIP
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 31 ++++++++++++++++++++
3 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 62a0eae77639..f1c53aec6523 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -95,6 +95,23 @@
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ sound_hdmi: sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
+ };
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s1>;
+ dai-tdm-slot-num = <2>;
+ dai-tdm-slot-width = <32>;
+ };
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -357,6 +374,19 @@
};
};
+ i2s1: i2s@5091000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-h6-i2s";
+ reg = <0x05091000 0x1000>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 4>;
+ resets = <&ccu RST_BUS_I2S1>;
+ dma-names = "tx";
+ allwinner,playback-channels = <8>;
+ };
+
usb2otg: usb@5100000 {
compatible = "allwinner,sun50i-h6-musb",
"allwinner,sun8i-a33-musb";
@@ -440,6 +470,7 @@
};
hdmi: hdmi@6000000 {
+ #sound-dai-cells = <0>;
compatible = "allwinner,sun50i-h6-dw-hdmi";
reg = <0x06000000 0x10000>;
reg-io-width = <1>;
--
2.21.0

View File

@ -1,442 +0,0 @@
From 0b2bbc6708ef986e2f8d281f65e0c1ca3ff14562 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Wed, 27 Mar 2019 13:21:06 +0100
Subject: [PATCH 1/5] net: stmmac: sun8i: Use devm_regulator_get for PHY
regulator
Use devm_regulator_get instead of devm_regulator_get_optional and rely
on dummy supply. This avoids NULL checks before regulator_enable/disable
calls.
This path also improves error reporting, because we now report both
use of dummy supply and error during registration with more detail,
instead of generic info level message "No regulator found" that
was reported previously on errors and lack of regulator property in DT.
Finally, we'll be adding further optional regulators, and the overall
code will be simpler.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 23 ++++++++-----------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index ddcc191febdb..906d46e2d166 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -528,12 +528,10 @@ static int sun8i_dwmac_init(struct platform_device *pdev, void *priv)
struct sunxi_priv_data *gmac = priv;
int ret;
- if (gmac->regulator) {
- ret = regulator_enable(gmac->regulator);
- if (ret) {
- dev_err(&pdev->dev, "Fail to enable regulator\n");
- return ret;
- }
+ ret = regulator_enable(gmac->regulator);
+ if (ret) {
+ dev_err(&pdev->dev, "Fail to enable regulator\n");
+ return ret;
}
ret = clk_prepare_enable(gmac->tx_clk);
@@ -998,8 +996,7 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
clk_disable_unprepare(gmac->tx_clk);
- if (gmac->regulator)
- regulator_disable(gmac->regulator);
+ regulator_disable(gmac->regulator);
}
static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
@@ -1135,12 +1132,12 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
}
/* Optional regulator for PHY */
- gmac->regulator = devm_regulator_get_optional(dev, "phy");
+ gmac->regulator = devm_regulator_get(dev, "phy");
if (IS_ERR(gmac->regulator)) {
- if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- dev_info(dev, "No regulator found\n");
- gmac->regulator = NULL;
+ ret = PTR_ERR(gmac->regulator);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get PHY regulator (%d)\n", ret);
+ return ret;
}
/* The "GMAC clock control" register might be located in the
--
2.24.0
From 4335e41db5678cf2a766c19e4fa79ffa5e4dca81 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:29:29 +0200
Subject: [PATCH 2/5] net: stmmac: sun8i: Rename PHY regulator variable to
regulator_phy
We'll be adding further optional regulators, and this makes it clearer
what the regulator is for.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 32 ++++++++++---------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 906d46e2d166..5d4ee99ca80e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -57,19 +57,21 @@ struct emac_variant {
};
/* struct sunxi_priv_data - hold all sunxi private data
- * @tx_clk: reference to MAC TX clock
- * @ephy_clk: reference to the optional EPHY clock for the internal PHY
- * @regulator: reference to the optional regulator
- * @rst_ephy: reference to the optional EPHY reset for the internal PHY
- * @variant: reference to the current board variant
- * @regmap: regmap for using the syscon
- * @internal_phy_powered: Does the internal PHY is enabled
- * @mux_handle: Internal pointer used by mdio-mux lib
+ * @tx_clk: reference to MAC TX clock
+ * @ephy_clk: reference to the optional EPHY clock for
+ * the internal PHY
+ * @regulator_phy: reference to the optional regulator
+ * @rst_ephy: reference to the optional EPHY reset for
+ * the internal PHY
+ * @variant: reference to the current board variant
+ * @regmap: regmap for using the syscon
+ * @internal_phy_powered: Does the internal PHY is enabled
+ * @mux_handle: Internal pointer used by mdio-mux lib
*/
struct sunxi_priv_data {
struct clk *tx_clk;
struct clk *ephy_clk;
- struct regulator *regulator;
+ struct regulator *regulator_phy;
struct reset_control *rst_ephy;
const struct emac_variant *variant;
struct regmap_field *regmap_field;
@@ -528,9 +530,9 @@ static int sun8i_dwmac_init(struct platform_device *pdev, void *priv)
struct sunxi_priv_data *gmac = priv;
int ret;
- ret = regulator_enable(gmac->regulator);
+ ret = regulator_enable(gmac->regulator_phy);
if (ret) {
- dev_err(&pdev->dev, "Fail to enable regulator\n");
+ dev_err(&pdev->dev, "Fail to enable PHY regulator\n");
return ret;
}
@@ -996,7 +998,7 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
clk_disable_unprepare(gmac->tx_clk);
- regulator_disable(gmac->regulator);
+ regulator_disable(gmac->regulator_phy);
}
static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
@@ -1132,9 +1134,9 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
}
/* Optional regulator for PHY */
- gmac->regulator = devm_regulator_get(dev, "phy");
- if (IS_ERR(gmac->regulator)) {
- ret = PTR_ERR(gmac->regulator);
+ gmac->regulator_phy = devm_regulator_get(dev, "phy");
+ if (IS_ERR(gmac->regulator_phy)) {
+ ret = PTR_ERR(gmac->regulator_phy);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get PHY regulator (%d)\n", ret);
return ret;
--
2.24.0
From 5f2f079f8bec44f9a5d07767b12d3eb7ad247012 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:31:38 +0200
Subject: [PATCH 3/5] net: stmmac: sun8i: Add support for enabling a regulator
for PHY I/O pins
Orange Pi 3 has two regulators that power the Realtek RTL8211E. According
to the phy datasheet, both regulators need to be enabled at the same time.
Add support for the second optional regulator, "phy-io", to the glue
driver.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 30 ++++++++++++++++---
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 5d4ee99ca80e..a7ffee494488 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -61,6 +61,8 @@ struct emac_variant {
* @ephy_clk: reference to the optional EPHY clock for
* the internal PHY
* @regulator_phy: reference to the optional regulator
+ * @regulator_phy_io: reference to the optional regulator for
+ * PHY I/O pins
* @rst_ephy: reference to the optional EPHY reset for
* the internal PHY
* @variant: reference to the current board variant
@@ -72,6 +74,7 @@ struct sunxi_priv_data {
struct clk *tx_clk;
struct clk *ephy_clk;
struct regulator *regulator_phy;
+ struct regulator *regulator_phy_io;
struct reset_control *rst_ephy;
const struct emac_variant *variant;
struct regmap_field *regmap_field;
@@ -530,21 +533,30 @@ static int sun8i_dwmac_init(struct platform_device *pdev, void *priv)
struct sunxi_priv_data *gmac = priv;
int ret;
+ ret = regulator_enable(gmac->regulator_phy_io);
+ if (ret) {
+ dev_err(&pdev->dev, "Fail to enable PHY I/O regulator\n");
+ return ret;
+ }
+
ret = regulator_enable(gmac->regulator_phy);
if (ret) {
dev_err(&pdev->dev, "Fail to enable PHY regulator\n");
- return ret;
+ goto err_disable_regulator_phy_io;
}
ret = clk_prepare_enable(gmac->tx_clk);
if (ret) {
- if (gmac->regulator)
- regulator_disable(gmac->regulator);
dev_err(&pdev->dev, "Could not enable AHB clock\n");
- return ret;
+ goto err_disable_regulator_phy;
}
return 0;
+err_disable_regulator_phy:
+ regulator_disable(gmac->regulator_phy);
+err_disable_regulator_phy_io:
+ regulator_disable(gmac->regulator_phy_io);
+ return ret;
}
static void sun8i_dwmac_core_init(struct mac_device_info *hw,
@@ -999,6 +1011,7 @@ static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
clk_disable_unprepare(gmac->tx_clk);
regulator_disable(gmac->regulator_phy);
+ regulator_disable(gmac->regulator_phy_io);
}
static void sun8i_dwmac_set_mac_loopback(void __iomem *ioaddr, bool enable)
@@ -1142,6 +1155,15 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
return ret;
}
+ /* Optional regulator for PHY I/O pins */
+ gmac->regulator_phy_io = devm_regulator_get(dev, "phy-io");
+ if (IS_ERR(gmac->regulator_phy_io)) {
+ ret = PTR_ERR(gmac->regulator_phy_io);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get PHY I/O regulator (%d)\n", ret);
+ return ret;
+ }
+
/* The "GMAC clock control" register might be located in the
* CCU address range (on the R40), or the system control address
* range (on most other sun8i and later SoCs).
--
2.24.0
From 1bb9d9c95dc6fdb5cc7f9f39166274cd47365f9a Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:54:48 +0200
Subject: [PATCH 4/5] arm64: dts: allwinner: orange-pi-3: Enable ethernet
Orange Pi 3 has two regulators that power the Realtek RTL8211E
PHY. According to the datasheet, both regulators need to be enabled
at the same time, or that "phy-io" should be enabled slightly earlier
than "phy" regulator.
RTL8211E/RTL8211EG datasheet says:
Note 4: 2.5V (or 1.8/1.5V) RGMII power should be risen simultaneously
or slightly earlier than 3.3V power. Rising 2.5V (or 1.8/1.5V) power
later than 3.3V power may lead to errors.
The driver ensures the regulator enable ordering. The timing is set
in DT via startup-delay-us.
We also need to wait at least 30ms after power-up/reset, before
accessing the PHY registers.
All values of RX/TX delay were tested exhaustively and a middle one
of the range of working values was chosen.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../dts/allwinner/sun50i-h6-orangepi-3.dts | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
index eb379cd402ac..b5dc419d92de 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts
@@ -15,6 +15,7 @@ / {
aliases {
serial0 = &uart0;
serial1 = &uart1;
+ ethernet0 = &emac;
};
chosen {
@@ -57,6 +58,15 @@ reg_vcc5v: vcc5v {
regulator-always-on;
};
+ reg_gmac_2v5: gmac-2v5 {
+ compatible = "regulator-fixed";
+ regulator-name = "gmac-2v5";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ enable-active-high;
+ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
+ };
+
reg_vcc33_wifi: vcc33-wifi {
/* Always on 3.3V regulator for WiFi and BT */
compatible = "regulator-fixed";
@@ -112,6 +122,35 @@ hdmi_out_con: endpoint {
};
};
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_rgmii_pins>;
+ phy-mode = "rgmii-txid";
+ phy-handle = <&ext_rgmii_phy>;
+ /*
+ * The board uses 2.5V RGMII signalling. Power sequence to enable
+ * the phy is to enable GMAC-2V5 and GMAC-3V (aldo2) power rails
+ * at the same time and to wait 100ms. The driver enables phy-io
+ * first. Delay is achieved with enable-ramp-delay on reg_aldo2.
+ */
+ phy-supply = <&reg_aldo2>;
+ phy-io-supply = <&reg_gmac_2v5>;
+ allwinner,rx-delay-ps = <1500>;
+ allwinner,tx-delay-ps = <700>;
+ status = "okay";
+};
+
+&mdio {
+ ext_rgmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+
+ reset-gpios = <&pio 3 14 GPIO_ACTIVE_LOW>; /* PD14 */
+ reset-assert-us = <15000>;
+ reset-deassert-us = <40000>;
+ };
+};
+
&mmc0 {
vmmc-supply = <&reg_cldo1>;
cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
@@ -182,6 +221,7 @@ reg_aldo2: aldo2 {
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-name = "vcc33-audio-tv-ephy-mac";
+ regulator-enable-ramp-delay = <100000>;
};
/* ALDO3 is shorted to CLDO1 */
--
2.24.0
From e6700b102c319f31165de2361830c24f182f69b6 Mon Sep 17 00:00:00 2001
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 20 Aug 2019 14:34:57 +0200
Subject: [PATCH 5/5] net: stmmac: sun8i: Fix reboot issue with ethernet on
Orange Pi 3
We disable both phy regulators before reboot, so that they are in a
known state on the next boot. This should be done in u-boot, but
it doesn't support AXP806 yet, thus this workaround.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index a7ffee494488..f7c7d89da7f8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -17,6 +17,7 @@
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/stmmac.h>
@@ -80,6 +81,7 @@ struct sunxi_priv_data {
struct regmap_field *regmap_field;
bool internal_phy_powered;
void *mux_handle;
+ struct notifier_block reboot_nb;
};
/* EMAC clock register @ 0x30 in the "system control" address range */
@@ -1111,6 +1113,19 @@ static struct regmap *sun8i_dwmac_get_syscon_from_dev(struct device_node *node)
return regmap;
}
+
+static int sun8i_dwmac_reboot_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct sunxi_priv_data *gmac = container_of(nb, struct sunxi_priv_data,
+ reboot_nb);
+
+ regulator_disable(gmac->regulator_phy);
+ regulator_disable(gmac->regulator_phy_io);
+
+ return NOTIFY_DONE;
+}
+
static int sun8i_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -1164,6 +1179,13 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
return ret;
}
+ gmac->reboot_nb.notifier_call = sun8i_dwmac_reboot_notifier;
+ ret = devm_register_reboot_notifier(dev, &gmac->reboot_nb);
+ if (ret) {
+ dev_err(dev, "Failed to register reboot notifier (%d)\n", ret);
+ return ret;
+ }
+
/* The "GMAC clock control" register might be located in the
* CCU address range (on the R40), or the system control address
* range (on most other sun8i and later SoCs).
--
2.24.0

View File

@ -1,159 +0,0 @@
From e6cdedb22a9b012366d07276dace02c2c98fffc4 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 15 Jan 2020 18:39:17 +0100
Subject: [PATCH 1/3] arm64: dts: allwinner: h6: tanix-tx6: enable emmc
Tanix TX6 has 32 GiB eMMC. Add a node for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-tanix-tx6.dts | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
index 83e6cb0e59ce..8cbf4e4a761e 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
@@ -31,6 +31,13 @@ hdmi_con_in: endpoint {
};
};
+ reg_vcc1v8: vcc1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
reg_vcc3v3: vcc3v3 {
compatible = "regulator-fixed";
regulator-name = "vcc3v3";
@@ -78,6 +85,15 @@ &mmc0 {
status = "okay";
};
+&mmc2 {
+ vmmc-supply = <&reg_vcc3v3>;
+ vqmmc-supply = <&reg_vcc1v8>;
+ non-removable;
+ cap-mmc-hw-reset;
+ bus-width = <8>;
+ status = "okay";
+};
+
&ohci0 {
status = "okay";
};
@@ -86,6 +102,10 @@ &ohci3 {
status = "okay";
};
+&pio {
+ vcc-pc-supply = <&reg_vcc1v8>;
+};
+
&r_ir {
linux,rc-map-name = "rc-tanix-tx5max";
status = "okay";
--
2.24.1
From cbf6129cdb69f006f66e22b854d5d544c940fd49 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 24 Aug 2019 01:03:05 +0200
Subject: [PATCH] Tanix TX6 improvements
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-tanix-tx6.dts | 44 +++++++++++++++++++
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 7 +++
2 files changed, 51 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
index 7e7cb10e3d96..3de430b631f2 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts
@@ -14,6 +14,7 @@
compatible = "oranth,tanix-tx6", "allwinner,sun50i-h6";
aliases {
+ ethernet0 = &emac;
serial0 = &uart0;
};
@@ -41,14 +42,26 @@
};
};
+&ac200_pwm_clk {
+ status = "okay";
+};
+
&de {
status = "okay";
};
&dwc3 {
status = "okay";
};
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_rmii_pins>;
+ phy-mode = "rmii";
+ phy-handle = <&ext_rmii_phy>;
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -63,6 +80,17 @@
};
};
+&i2c3 {
+ status = "okay";
+};
+
+&mdio {
+ ext_rmii_phy: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins>;
@@ -80,6 +116,10 @@
status = "okay";
};
+&pwm {
+ status = "okay";
+};
+
&r_ir {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 67b732e34091..e436fc78ac71 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -251,6 +251,13 @@
drive-strength = <40>;
};
+ ext_rmii_pins: rmii_pins {
+ pins = "PA0", "PA1", "PA2", "PA3", "PA4",
+ "PA5", "PA6", "PA7", "PA8", "PA9";
+ function = "emac";
+ drive-strength = <40>;
+ };
+
hdmi_pins: hdmi-pins {
pins = "PH8", "PH9", "PH10";
function = "hdmi";
--
2.23.0

View File

@ -1,24 +0,0 @@
From 3e9d104275c44ab1711a3564ce67cabe850afe75 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Thu, 2 Jan 2020 19:07:29 +0100
Subject: [PATCH] Add frame inversion to correct multi-channel audio
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 132ef9c2d348..43ed134b49f7 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -103,6 +103,7 @@
simple-audio-card,format = "i2s";
simple-audio-card,name = "allwinner-hdmi";
simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
simple-audio-card,codec {
sound-dai = <&hdmi>;
--
2.24.1

View File

@ -1,101 +0,0 @@
From 23fa74407f0c71e06e10cb55ca64722b97d924f0 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 29 Oct 2020 20:58:55 +0100
Subject: [PATCH] arm64: dts: allwinner: h6: PineH64 model B: Add wifi
PineH64 model B contains RTL8723CS wifi+bt combo module.
Since bluetooth support is not yet squared away, only wifi is enabled
for now.
Acked-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-pine-h64-model-b.dts | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
index f4c8966a6497..7fea1e4e2d49 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
@@ -10,6 +10,12 @@ / {
compatible = "pine64,pine-h64-model-b", "allwinner,sun50i-h6";
/delete-node/ reg_gmac_3v3;
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
+ post-power-on-delay-ms = <200>;
+ };
};
&hdmi_connector {
@@ -19,3 +25,12 @@ &hdmi_connector {
&emac {
phy-supply = <&reg_aldo2>;
};
+
+&mmc1 {
+ vmmc-supply = <&reg_cldo3>;
+ vqmmc-supply = <&reg_aldo1>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
--
2.29.1
From 1f08c8dbef8c4f9590e1de0169e1d004a23ed721 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 29 Oct 2020 21:04:24 +0100
Subject: [PATCH 2/2] pineh64 model b - bluetooth wip
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../dts/allwinner/sun50i-h6-pine-h64-model-b.dts | 16 ++++++++++++++++
drivers/bluetooth/hci_h5.c | 3 +++
2 files changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
index 3f42b8b29b0f..99732e5850c2 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
@@ -33,3 +33,19 @@ &mmc1 {
non-removable;
status = "okay";
};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+
+ bluetooth {
+ compatible = "realtek,rtl8723bs-bt";
+ device-wakeup-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
+ host-wakeup-gpios = <&r_pio 1 1 GPIO_ACTIVE_HIGH>; /* PM1 */
+ enable-gpios = <&r_pio 1 4 GPIO_ACTIVE_HIGH>; /* PM4 */
+ firmware-postfix = "OBDA8723";
+ max-speed = <1500000>;
+ };
+};
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c
index a10d710fc3f1..c2fcb3429277 100644
--- a/drivers/bluetooth/hci_h5.c
+++ b/drivers/bluetooth/hci_h5.c
@@ -821,6 +821,9 @@ static int h5_serdev_probe(struct serdev_device *serdev)
if (!data)
return -ENODEV;
+ of_property_read_string(dev->of_node,
+ "firmware-postfix", &h5->id);
+
h5->vnd = (const struct h5_vnd *)data;
}
--
2.29.1

View File

@ -1,36 +0,0 @@
#
# Configuration for H3 analog output
#
<confdir:pcm/front.conf>
H3_Audio_Codec.pcm.front.0 {
@args [ CARD ]
@args.CARD {
type string
}
type hooks
slave.pcm {
type hw
card $CARD
}
hooks.0 {
type ctl_elems
hook_args [
{
name "Line Out Playback Volume"
lock true
preserve true
optional false
value 31
}
{
name "Line Out Playback Switch"
lock true
preserve true
optional false
value [ on on ]
}
]
}
}

View File

@ -0,0 +1,35 @@
From 8e2b67acc77a0c7704b2001dd4bf8646f286e4be Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 16 Jan 2021 13:09:00 +0100
Subject: [PATCH] ARM: dts: sun8i: r40: Add timer node
Allwinner R40 has a timer.
Add a node for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/boot/dts/sun8i-r40.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -647,6 +647,18 @@
};
};
+ timer@1c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0x90>;
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
+ };
+
wdt: watchdog@1c20c90 {
compatible = "allwinner,sun4i-a10-wdt";
reg = <0x01c20c90 0x10>;

View File

@ -0,0 +1,57 @@
From 958ad802878443a2f5f06f5f3c796d163fd03ca9 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Mon, 24 Aug 2020 16:35:54 +0200
Subject: [PATCH 16/17] dts: enable analog codec
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../boot/dts/sun8i-r40-bananapi-m2-ultra.dts | 9 ++++
arch/arm/boot/dts/sun8i-r40.dtsi | 42 +++++++++++++++++++
2 files changed, 51 insertions(+)
--- a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
+++ b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -113,6 +113,15 @@
status = "okay";
};
+&codec {
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Headphone", "HPCOM",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
&de {
status = "okay";
};
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -692,6 +692,25 @@
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-codec";
+ reg = <0x01c22c00 0x300>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_CODEC>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_BUS_CODEC>;
+ dmas = <&dma 19>, <&dma 19>;
+ dma-names = "rx", "tx";
+ allwinner,codec-analog-controls = <&codec_analog>;
+ status = "disabled";
+ };
+
+ codec_analog: codec-analog@01c22f00 {
+ compatible = "allwinner,sun8i-a23-codec-analog";
+ reg = <0x01c22f00 0x4>;
+ };
+
ths: thermal-sensor@1c24c00 {
compatible = "allwinner,sun8i-r40-ths";
reg = <0x01c24c00 0x100>;

View File

@ -8,11 +8,9 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
arch/arm/boot/dts/sun8i-r40.dtsi | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index 6dc075de94ae..bd8f4495ad7a 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -111,6 +111,24 @@ de: display-engine {
@@ -111,6 +111,24 @@
status = "disabled";
};
@ -37,7 +35,7 @@ index 6dc075de94ae..bd8f4495ad7a 100644
thermal-zones {
cpu_thermal: cpu0-thermal {
/* milliseconds */
@@ -647,6 +665,19 @@ wdt: watchdog@1c20c90 {
@@ -666,6 +684,19 @@
clocks = <&osc24M>;
};
@ -57,7 +55,7 @@ index 6dc075de94ae..bd8f4495ad7a 100644
ir0: ir@1c21800 {
compatible = "allwinner,sun8i-r40-ir",
"allwinner,sun6i-a31-ir";
@@ -1134,6 +1165,7 @@ gic: interrupt-controller@1c81000 {
@@ -1142,6 +1173,7 @@
};
hdmi: hdmi@1ee0000 {
@ -65,6 +63,3 @@ index 6dc075de94ae..bd8f4495ad7a 100644
compatible = "allwinner,sun8i-r40-dw-hdmi",
"allwinner,sun8i-a83t-dw-hdmi";
reg = <0x01ee0000 0x10000>;
--
2.28.0

View File

@ -1,112 +0,0 @@
From 7ace610aa8c87a4854c974299f880f168a8b075d Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Mon, 24 Aug 2020 16:35:00 +0200
Subject: [PATCH 15/17] clk: r40: initialize clocks earlier
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/clk/sunxi-ng/ccu-sun8i-r40.c | 63 +++++++++++++++++-----------
1 file changed, 38 insertions(+), 25 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
index 84153418453f..5c82fed4b4b9 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c
@@ -5,6 +5,7 @@
#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -1310,14 +1311,46 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev)
struct resource *res;
struct regmap *regmap;
void __iomem *reg;
- u32 val;
- int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(reg))
return PTR_ERR(reg);
+ regmap = devm_regmap_init_mmio(&pdev->dev, reg,
+ &sun8i_r40_ccu_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return 0;
+}
+
+static const struct of_device_id sun8i_r40_ccu_ids[] = {
+ { .compatible = "allwinner,sun8i-r40-ccu" },
+ { }
+};
+
+static struct platform_driver sun8i_r40_ccu_driver = {
+ .probe = sun8i_r40_ccu_probe,
+ .driver = {
+ .name = "sun8i-r40-ccu",
+ .of_match_table = sun8i_r40_ccu_ids,
+ },
+};
+builtin_platform_driver(sun8i_r40_ccu_driver);
+
+static void __init sun8i_r40_ccu_setup(struct device_node *node)
+{
+ void __iomem *reg;
+ u32 val;
+ int ret;
+
+ reg = of_iomap(node, 0);
+ if (IS_ERR(reg)) {
+ pr_err("%pOF: Could not map the clock registers\n", node);
+ return;
+ }
+
/* Force the PLL-Audio-1x divider to 1 */
val = readl(reg + SUN8I_R40_PLL_AUDIO_REG);
val &= ~GENMASK(19, 16);
@@ -1341,14 +1374,7 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev)
writel(SUN8I_R40_SYS_32K_CLK_KEY | BIT(8),
reg + SUN8I_R40_SYS_32K_CLK_REG);
- regmap = devm_regmap_init_mmio(&pdev->dev, reg,
- &sun8i_r40_ccu_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_r40_ccu_desc);
- if (ret)
- return ret;
+ sunxi_ccu_probe(node, reg, &sun8i_r40_ccu_desc);
/* Gate then ungate PLL CPU after any rate changes */
ccu_pll_notifier_register(&sun8i_r40_pll_cpu_nb);
@@ -1357,19 +1383,6 @@ static int sun8i_r40_ccu_probe(struct platform_device *pdev)
ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk,
&sun8i_r40_cpu_nb);
- return 0;
}
-
-static const struct of_device_id sun8i_r40_ccu_ids[] = {
- { .compatible = "allwinner,sun8i-r40-ccu" },
- { }
-};
-
-static struct platform_driver sun8i_r40_ccu_driver = {
- .probe = sun8i_r40_ccu_probe,
- .driver = {
- .name = "sun8i-r40-ccu",
- .of_match_table = sun8i_r40_ccu_ids,
- },
-};
-builtin_platform_driver(sun8i_r40_ccu_driver);
+CLK_OF_DECLARE_DRIVER(sun8i_r40_ccu, "allwinner,sun8i-r40-ccu",
+ sun8i_r40_ccu_setup);
--
2.28.0

View File

@ -1,101 +0,0 @@
From 958ad802878443a2f5f06f5f3c796d163fd03ca9 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Mon, 24 Aug 2020 16:35:54 +0200
Subject: [PATCH 16/17] dts: enable various devices
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../boot/dts/sun8i-r40-bananapi-m2-ultra.dts | 9 ++++
arch/arm/boot/dts/sun8i-r40.dtsi | 42 +++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
index 2fc62ef0cb3e..dc673826109f 100644
--- a/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
+++ b/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dts
@@ -113,6 +113,15 @@ &ahci {
status = "okay";
};
+&codec {
+ allwinner,audio-routing =
+ "Headphone", "HP",
+ "Headphone", "HPCOM",
+ "MIC1", "Mic",
+ "Mic", "MBIAS";
+ status = "okay";
+};
+
&de {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index 7907569e7b5c..6dc075de94ae 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -628,6 +628,18 @@ uart3_rts_cts_pg_pins: uart3-rts-cts-pg-pins {
};
};
+ timer@1c20c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x01c20c00 0x90>;
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&osc24M>;
+ };
+
wdt: watchdog@1c20c90 {
compatible = "allwinner,sun4i-a10-wdt";
reg = <0x01c20c90 0x10>;
@@ -661,6 +673,25 @@ ir1: ir@1c21c00 {
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-codec";
+ reg = <0x01c22c00 0x300>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_CODEC>;
+ clock-names = "apb", "codec";
+ resets = <&ccu RST_BUS_CODEC>;
+ dmas = <&dma 19>, <&dma 19>;
+ dma-names = "rx", "tx";
+ allwinner,codec-analog-controls = <&codec_analog>;
+ status = "disabled";
+ };
+
+ codec_analog: codec-analog@01c22f00 {
+ compatible = "allwinner,sun8i-a23-codec-analog";
+ reg = <0x01c22f00 0x4>;
+ };
+
ths: thermal-sensor@1c24c00 {
compatible = "allwinner,sun8i-r40-ths";
reg = <0x01c24c00 0x100>;
@@ -866,6 +897,17 @@ gmac_mdio: mdio {
};
};
+ hstimer@1c60000 {
+ compatible = "allwinner,sun7i-a20-hstimer";
+ reg = <0x01c60000 0x1000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_HSTIMER>;
+ resets = <&ccu RST_BUS_HSTIMER>;
+ };
+
mbus: dram-controller@1c62000 {
compatible = "allwinner,sun8i-r40-mbus";
reg = <0x01c62000 0x1000>;
--
2.28.0

View File

@ -3686,7 +3686,6 @@ CONFIG_DRM_SUN4I=y
# CONFIG_DRM_SUN4I_BACKEND is not set
# CONFIG_DRM_SUN6I_DSI is not set
CONFIG_DRM_SUN8I_DW_HDMI=y
CONFIG_DRM_SUN8I_DW_HDMI_CEC=y
CONFIG_DRM_SUN8I_MIXER=y
CONFIG_DRM_SUN8I_TCON_TOP=y
CONFIG_DRM_PANEL=y

View File

@ -3613,7 +3613,6 @@ CONFIG_DRM_SUN4I_HDMI_CEC=y
CONFIG_DRM_SUN4I_BACKEND=y
CONFIG_DRM_SUN6I_DSI=y
CONFIG_DRM_SUN8I_DW_HDMI=y
CONFIG_DRM_SUN8I_DW_HDMI_CEC=y
CONFIG_DRM_SUN8I_MIXER=y
CONFIG_DRM_SUN8I_TCON_TOP=y
# CONFIG_DRM_OMAP is not set

View File

@ -1,7 +1,7 @@
From 343bbfd1652964fb52520c4cc232c5a2c679cb21 Mon Sep 17 00:00:00 2001
From 9a7e6c2d8a18a24b013c1ad165ed04bb7d2c7716 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 25 Aug 2020 19:35:22 +0200
Subject: [PATCH] media: cedrus: Add support for R40
Subject: [PATCH 01/44] media: cedrus: Add support for R40
Video engine in R40 is very similar to that in A33 but it runs on lower
speed, at least according to OS images released by board designer.
@ -13,11 +13,9 @@ Link: https://lore.kernel.org/r/20200825173523.1289379-5-jernej.skrabec@siol.net
drivers/staging/media/sunxi/cedrus/cedrus.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
index bc27f9430eeb..83a654a618be 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -496,6 +496,11 @@ static const struct cedrus_variant sun8i_h3_cedrus_variant = {
@@ -508,6 +508,11 @@ static const struct cedrus_variant sun8i
.mod_rate = 402000000,
};
@ -29,17 +27,14 @@ index bc27f9430eeb..83a654a618be 100644
static const struct cedrus_variant sun50i_a64_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED |
CEDRUS_CAPABILITY_H265_DEC,
@@ -536,6 +541,10 @@ static const struct of_device_id cedrus_dt_match[] = {
.compatible = "allwinner,sun8i-h3-video-engine",
@@ -549,6 +554,10 @@ static const struct of_device_id cedrus_
.data = &sun8i_h3_cedrus_variant,
},
+ {
{
+ .compatible = "allwinner,sun8i-r40-video-engine",
+ .data = &sun8i_r40_cedrus_variant,
+ },
{
+ {
.compatible = "allwinner,sun50i-a64-video-engine",
.data = &sun50i_a64_cedrus_variant,
--
2.28.0
},

View File

@ -1,7 +1,7 @@
From 371443de3c991f7b025d5203754a3497b7ea7c32 Mon Sep 17 00:00:00 2001
From f710d6403b7716d7a5319e51c4cb3c217ec85b73 Mon Sep 17 00:00:00 2001
From: Sean Young <sean@mess.org>
Date: Tue, 10 Nov 2020 09:30:38 +0100
Subject: [PATCH] media: sunxi-cir: allow timeout to be set at runtime
Subject: [PATCH 02/44] media: sunxi-cir: allow timeout to be set at runtime
This allows the timeout to be set with the LIRC_SET_REC_TIMEOUT ioctl.
@ -18,8 +18,6 @@ Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/rc/sunxi-cir.c | 48 ++++++++++++++++++++++++++++++------
1 file changed, 40 insertions(+), 8 deletions(-)
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 4afc5895bee7..8555c7798706 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -73,10 +73,6 @@
@ -33,7 +31,7 @@ index 4afc5895bee7..8555c7798706 100644
/**
* struct sunxi_ir_quirks - Differences between SoC variants.
@@ -146,6 +142,41 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
@@ -146,6 +142,41 @@ static irqreturn_t sunxi_ir_irq(int irqn
return IRQ_HANDLED;
}
@ -75,7 +73,7 @@ index 4afc5895bee7..8555c7798706 100644
static int sunxi_ir_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -242,9 +273,11 @@ static int sunxi_ir_probe(struct platform_device *pdev)
@@ -242,9 +273,11 @@ static int sunxi_ir_probe(struct platfor
ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
ir->rc->dev.parent = dev;
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
@ -89,7 +87,7 @@ index 4afc5895bee7..8555c7798706 100644
ir->rc->driver_name = SUNXI_IR_DEV;
ret = rc_register_device(ir->rc);
@@ -272,8 +305,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
@@ -272,8 +305,7 @@ static int sunxi_ir_probe(struct platfor
writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG);
/* Set noise threshold and idle threshold */
@ -99,6 +97,3 @@ index 4afc5895bee7..8555c7798706 100644
/* Invert Input Signal */
writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);
--
2.30.0

View File

@ -0,0 +1,118 @@
From a8bdfe3893f9b226492dac4b4e0d37a27dbee201 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
Date: Fri, 30 Oct 2020 15:46:35 +0100
Subject: [PATCH 03/44] ASoC: sun4i-i2s: Change set_chan_cfg() params
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
As slots and slot_width can be set manually using set_tdm().
These values are then kept in sun4i_i2s struct.
So we need to check if these values are set or not.
This is not done actually and will trigger a bug.
For example, if we set to the simple soundcard in the device-tree
dai-tdm-slot-width = <32> and then start a stream using S16_LE,
currently we would calculate BCLK for 32-bit slots, but program
lrck_period for 16-bit slots, making the sample rate double what we
expected.
To fix this, we need to check if these values are set or not but as
this logic is already done by the caller. Avoid duplicating this
logic and just pass the required values as params to set_chan_cfg().
Suggested-by: Samuel Holland <samuel@sholland.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-3-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -162,8 +162,15 @@ struct sun4i_i2s_quirks {
unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
s8 (*get_sr)(const struct sun4i_i2s *, int);
s8 (*get_wss)(const struct sun4i_i2s *, int);
- int (*set_chan_cfg)(const struct sun4i_i2s *,
- const struct snd_pcm_hw_params *);
+
+ /*
+ * In the set_chan_cfg() function pointer:
+ * @slots: channels per frame + padding slots, regardless of format
+ * @slot_width: bits per sample + padding bits, regardless of format
+ */
+ int (*set_chan_cfg)(const struct sun4i_i2s *i2s,
+ unsigned int channels, unsigned int slots,
+ unsigned int slot_width);
int (*set_fmt)(const struct sun4i_i2s *, unsigned int);
};
@@ -399,10 +406,9 @@ static s8 sun8i_i2s_get_sr_wss(const str
}
static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
- const struct snd_pcm_hw_params *params)
+ unsigned int channels, unsigned int slots,
+ unsigned int slot_width)
{
- unsigned int channels = params_channels(params);
-
/* Map the channels for playback and capture */
regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
@@ -419,15 +425,11 @@ static int sun4i_i2s_set_chan_cfg(const
}
static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
- const struct snd_pcm_hw_params *params)
+ unsigned int channels, unsigned int slots,
+ unsigned int slot_width)
{
- unsigned int channels = params_channels(params);
- unsigned int slots = channels;
unsigned int lrck_period;
- if (i2s->slots)
- slots = i2s->slots;
-
/* Map the channels for playback and capture */
regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
@@ -450,13 +452,13 @@ static int sun8i_i2s_set_chan_cfg(const
switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
- lrck_period = params_physical_width(params) * slots;
+ lrck_period = slot_width * slots;
break;
case SND_SOC_DAIFMT_LEFT_J:
case SND_SOC_DAIFMT_RIGHT_J:
case SND_SOC_DAIFMT_I2S:
- lrck_period = params_physical_width(params);
+ lrck_period = slot_width;
break;
default:
@@ -482,7 +484,9 @@ static int sun4i_i2s_hw_params(struct sn
unsigned int word_size = params_width(params);
unsigned int slot_width = params_physical_width(params);
unsigned int channels = params_channels(params);
+
unsigned int slots = channels;
+
int ret, sr, wss;
u32 width;
@@ -492,7 +496,7 @@ static int sun4i_i2s_hw_params(struct sn
if (i2s->slot_width)
slot_width = i2s->slot_width;
- ret = i2s->variant->set_chan_cfg(i2s, params);
+ ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width);
if (ret < 0) {
dev_err(dai->dev, "Invalid channel configuration\n");
return ret;

View File

@ -0,0 +1,295 @@
From 8ff0df5dffe58a2d1595a6e59ccd5ce63d6bf0e5 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 30 Oct 2020 15:46:36 +0100
Subject: [PATCH 04/44] ASoC: sun4i-i2s: Add support for H6 I2S
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
H6 I2S is very similar to that in H3, except it supports up to 16
channels.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-4-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 222 ++++++++++++++++++++++++++++++++++++
1 file changed, 222 insertions(+)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -124,6 +124,21 @@
#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
+/* Defines required for sun50i-h6 support */
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16)
+#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16)
+#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0)
+#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1))
+
+#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44
+#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48
+
+#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64
+#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68
+#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C
+
struct sun4i_i2s;
/**
@@ -476,6 +491,60 @@ static int sun8i_i2s_set_chan_cfg(const
return 0;
}
+static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+ unsigned int channels, unsigned int slots,
+ unsigned int slot_width)
+{
+ unsigned int lrck_period;
+
+ /* Map the channels for playback and capture */
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
+
+ /* Configure the channels */
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+ regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+
+ switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ lrck_period = slot_width * slots;
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_I2S:
+ lrck_period = slot_width;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+ SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
+ SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
+
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+ SUN50I_H6_I2S_TX_CHAN_EN(channels));
+
+ return 0;
+}
+
static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -703,6 +772,108 @@ static int sun8i_i2s_set_soc_fmt(const s
return 0;
}
+static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
+ unsigned int fmt)
+{
+ u32 mode, val;
+ u8 offset;
+
+ /*
+ * DAI clock polarity
+ *
+ * The setup for LRCK contradicts the datasheet, but under a
+ * scope it's clear that the LRCK polarity is reversed
+ * compared to the expected polarity on the bus.
+ */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert both clocks */
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Invert bit clock */
+ val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED |
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Invert frame clock */
+ val = 0;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
+ SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
+ SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
+ val);
+
+ /* DAI Mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ mode = SUN8I_I2S_CTRL_MODE_PCM;
+ offset = 1;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ mode = SUN8I_I2S_CTRL_MODE_PCM;
+ offset = 0;
+ break;
+
+ case SND_SOC_DAIFMT_I2S:
+ mode = SUN8I_I2S_CTRL_MODE_LEFT;
+ offset = 1;
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ mode = SUN8I_I2S_CTRL_MODE_LEFT;
+ offset = 0;
+ break;
+
+ case SND_SOC_DAIFMT_RIGHT_J:
+ mode = SUN8I_I2S_CTRL_MODE_RIGHT;
+ offset = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN8I_I2S_CTRL_MODE_MASK, mode);
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+ regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* BCLK and LRCLK master */
+ val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT;
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* BCLK and LRCLK slave */
+ val = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
+ val);
+
+ return 0;
+}
+
static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -983,6 +1154,22 @@ static const struct reg_default sun8i_i2
{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
};
+static const struct reg_default sun50i_h6_i2s_reg_defaults[] = {
+ { SUN4I_I2S_CTRL_REG, 0x00060000 },
+ { SUN4I_I2S_FMT0_REG, 0x00000033 },
+ { SUN4I_I2S_FMT1_REG, 0x00000030 },
+ { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
+ { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
+ { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
+ { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
+ { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
+ { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
+ { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
+};
+
static const struct regmap_config sun4i_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1010,6 +1197,19 @@ static const struct regmap_config sun8i_
.volatile_reg = sun8i_i2s_volatile_reg,
};
+static const struct regmap_config sun50i_h6_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN50I_H6_I2S_RX_CHAN_MAP1_REG,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = sun50i_h6_i2s_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults),
+ .writeable_reg = sun4i_i2s_wr_reg,
+ .readable_reg = sun8i_i2s_rd_reg,
+ .volatile_reg = sun8i_i2s_volatile_reg,
+};
+
static int sun4i_i2s_runtime_resume(struct device *dev)
{
struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -1168,6 +1368,24 @@ static const struct sun4i_i2s_quirks sun
.set_fmt = sun4i_i2s_set_soc_fmt,
};
+static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
+ .has_reset = true,
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
+ .bclk_dividers = sun8i_i2s_clk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
+ .mclk_dividers = sun8i_i2s_clk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
+ .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
+ .get_sr = sun8i_i2s_get_sr_wss,
+ .get_wss = sun8i_i2s_get_sr_wss,
+ .set_chan_cfg = sun50i_h6_i2s_set_chan_cfg,
+ .set_fmt = sun50i_h6_i2s_set_soc_fmt,
+};
+
static int sun4i_i2s_init_regmap_fields(struct device *dev,
struct sun4i_i2s *i2s)
{
@@ -1337,6 +1555,10 @@ static const struct of_device_id sun4i_i
.compatible = "allwinner,sun50i-a64-codec-i2s",
.data = &sun50i_a64_codec_i2s_quirks,
},
+ {
+ .compatible = "allwinner,sun50i-h6-i2s",
+ .data = &sun50i_h6_i2s_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_i2s_match);

View File

@ -1,752 +0,0 @@
From b5cb1681a065bd03b0eb84ca243bc50ab0fa54c1 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 17 Sep 2019 17:55:07 +0200
Subject: [PATCH] WIP: I2S improvements (to be mainlined)
Work done by Marcus Cooper (codekipper)
---
sound/soc/sunxi/sun4i-i2s.c | 454 ++++++++++++++++++++++++++++++++----
1 file changed, 412 insertions(+), 42 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d0a8d5810c0a..9a715a6bdbf9 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -23,7 +23,7 @@
#define SUN4I_I2S_CTRL_REG 0x00
#define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
-#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
+#define SUN4I_I2S_CTRL_SDO_EN(lines) (((1 << (lines)) - 1) << 8)
#define SUN4I_I2S_CTRL_MODE_MASK BIT(5)
#define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5)
#define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
@@ -48,6 +48,9 @@
#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
#define SUN4I_I2S_FMT1_REG 0x08
+#define SUN4I_I2S_FMT1_REG_SEXT_MASK BIT(8)
+#define SUN4I_I2S_FMT1_REG_SEXT(sext) ((sext) << 8)
+
#define SUN4I_I2S_FIFO_TX_REG 0x0c
#define SUN4I_I2S_FIFO_RX_REG 0x10
@@ -97,33 +100,53 @@
#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4)
#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19)
-#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
-#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19)
+#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19)
#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8)
#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8)
#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7)
-#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7)
-#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7)
+#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
+
+#define SUN8I_I2S_FMT1_REG_SEXT_MASK GENMASK(5, 4)
+#define SUN8I_I2S_FMT1_REG_SEXT(sext) ((sext) << 4)
#define SUN8I_I2S_INT_STA_REG 0x0c
#define SUN8I_I2S_FIFO_TX_REG 0x20
#define SUN8I_I2S_CHAN_CFG_REG 0x30
#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4)
-#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) ((chan - 1) << 4)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) (((chan) - 1) << 4)
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
-#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) ((chan) - 1)
#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
-#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset) ((offset) << 12)
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
+#define SUN8I_I2S_TX_CHAN_SEL_MASK GENMASK(2, 0)
+#define SUN8I_I2S_TX_CHAN_SEL(chan) ((chan) - 1)
#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
+/* Defines required for sun50i-h6 support */
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20)
+#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16)
+#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) (((chan) - 1) << 16)
+#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0)
+#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << (num_chan)) - 1))
+
+#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44
+#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48
+
+#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64
+#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68
+#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C
+
struct sun4i_i2s;
/**
@@ -156,7 +179,16 @@ struct sun4i_i2s_quirks {
s8 (*get_wss)(const struct sun4i_i2s *, int);
int (*set_chan_cfg)(const struct sun4i_i2s *,
const struct snd_pcm_hw_params *);
- int (*set_fmt)(const struct sun4i_i2s *, unsigned int);
+ int (*set_fmt)(struct sun4i_i2s *, unsigned int);
+ void (*set_fmt_sext)(const struct sun4i_i2s *, unsigned int);
+ void (*set_txchanoffset)(const struct sun4i_i2s *, int);
+ void (*set_rxchanoffset)(const struct sun4i_i2s *);
+ void (*set_txchanen)(const struct sun4i_i2s *, int, int);
+ void (*set_rxchanen)(const struct sun4i_i2s *, int);
+ void (*set_txchansel)(const struct sun4i_i2s *, int, int);
+ void (*set_rxchansel)(const struct sun4i_i2s *, int);
+ void (*set_txchanmap)(const struct sun4i_i2s *, int, int);
+ void (*set_rxchanmap)(const struct sun4i_i2s *, int);
};
struct sun4i_i2s {
@@ -169,6 +201,7 @@ struct sun4i_i2s {
unsigned int mclk_freq;
unsigned int slots;
unsigned int slot_width;
+ unsigned int offset;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -354,6 +387,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
+ /* Set sign extension to pad out LSB with 0 */
+ i2s->variant->set_fmt_sext(i2s, 0);
+
return 0;
}
@@ -396,8 +432,8 @@ static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
unsigned int channels = params_channels(params);
/* Map the channels for playback and capture */
- regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
- regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
+ i2s->variant->set_txchanmap(i2s, 0, 0x76543210);
+ i2s->variant->set_rxchanmap(i2s, 0x3210);
/* Configure the channels */
regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
@@ -421,16 +457,12 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
slots = i2s->slots;
/* Map the channels for playback and capture */
- regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
- regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
+ i2s->variant->set_txchanmap(i2s, 0, 0x76543210);
+ i2s->variant->set_rxchanmap(i2s, 0x3210);
/* Configure the channels */
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN4I_I2S_CHAN_SEL_MASK,
- SUN4I_I2S_CHAN_SEL(channels));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
- SUN4I_I2S_CHAN_SEL_MASK,
- SUN4I_I2S_CHAN_SEL(channels));
+ i2s->variant->set_txchansel(i2s, 0, channels);
+ i2s->variant->set_rxchansel(i2s, channels);
regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
@@ -448,7 +480,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
break;
case SND_SOC_DAIFMT_I2S:
- lrck_period = params_physical_width(params);
+ if (i2s->slot_width)
+ lrck_period = i2s->slot_width;
+ else
+ lrck_period = params_physical_width(params);
break;
default:
@@ -466,6 +501,166 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
return 0;
}
+static void sun8i_i2s_set_txchanoffset(const struct sun4i_i2s *i2s, int output)
+{
+ if (output >= 0 && output < 4)
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
+ SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset));
+}
+
+static void sun8i_i2s_set_rxchanoffset(const struct sun4i_i2s *i2s)
+{
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_RX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
+ SUN8I_I2S_TX_CHAN_OFFSET(i2s->offset));
+}
+
+static void sun50i_h6_i2s_set_txchanoffset(const struct sun4i_i2s *i2s, int output)
+{
+ if (output >= 0 && output < 4)
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(i2s->offset));
+}
+
+static void sun50i_h6_i2s_set_rxchanoffset(const struct sun4i_i2s *i2s)
+{
+ regmap_update_bits(i2s->regmap,
+ SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(i2s->offset));
+}
+
+static void sun8i_i2s_set_txchanen(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ if (output >= 0 && output < 4)
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
+ SUN8I_I2S_TX_CHAN_EN_MASK,
+ SUN8I_I2S_TX_CHAN_EN(channel));
+}
+
+static void sun8i_i2s_set_rxchanen(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_RX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_EN_MASK,
+ SUN8I_I2S_TX_CHAN_EN(channel));
+}
+
+static void sun50i_h6_i2s_set_txchanen(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ if (output >= 0 && output < 4)
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
+ SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+ SUN50I_H6_I2S_TX_CHAN_EN(channel));
+}
+
+static void sun50i_h6_i2s_set_rxchanen(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_update_bits(i2s->regmap,
+ SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+ SUN50I_H6_I2S_TX_CHAN_EN(channel));
+}
+
+static void sun4i_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ /* Configure the channels */
+ regmap_write(i2s->regmap,
+ SUN4I_I2S_TX_CHAN_SEL_REG,
+ SUN4I_I2S_CHAN_SEL(channel));
+}
+
+static void sun8i_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ if (output >= 0 && output < 4)
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
+ SUN8I_I2S_TX_CHAN_SEL_MASK,
+ SUN8I_I2S_TX_CHAN_SEL(channel));
+}
+
+static void sun4i_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
+{
+ /* Configure the channels */
+ regmap_write(i2s->regmap,
+ SUN4I_I2S_RX_CHAN_SEL_REG,
+ SUN4I_I2S_CHAN_SEL(channel));
+}
+
+static void sun8i_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_RX_CHAN_SEL_REG,
+ SUN8I_I2S_TX_CHAN_SEL_MASK,
+ SUN8I_I2S_TX_CHAN_SEL(channel));
+}
+
+static void sun50i_h6_i2s_set_txchansel(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ if (output >= 0 && output < 4)
+ regmap_update_bits(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_SEL_REG + (output * 4),
+ SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL(channel));
+}
+
+static void sun50i_h6_i2s_set_rxchansel(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_update_bits(i2s->regmap,
+ SUN50I_H6_I2S_RX_CHAN_SEL_REG,
+ SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL(channel));
+}
+
+static void sun4i_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, channel);
+}
+
+static void sun8i_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ if (output >= 0 && output < 4)
+ regmap_write(i2s->regmap,
+ SUN8I_I2S_TX_CHAN_MAP_REG + (output * 4), channel);
+}
+
+static void sun4i_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, channel);
+}
+
+static void sun8i_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, channel);
+}
+
+static void sun50i_h6_i2s_set_txchanmap(const struct sun4i_i2s *i2s, int output,
+ int channel)
+{
+ if (output >= 0 && output < 4)
+ regmap_write(i2s->regmap,
+ SUN50I_H6_I2S_TX_CHAN_MAP1_REG + (output * 8), channel);
+}
+
+static void sun50i_h6_i2s_set_rxchanmap(const struct sun4i_i2s *i2s, int channel)
+{
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, channel);
+}
+
static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -477,6 +672,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
unsigned int slots = channels;
int ret, sr, wss;
u32 width;
+ int lines;
if (i2s->slots)
slots = i2s->slots;
@@ -490,10 +686,82 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (channels > dai->driver->playback.channels_max ||
+ channels < dai->driver->playback.channels_min) {
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
+ channels);
+ return -EINVAL;
+ }
+
+ lines = (channels + 1) / 2;
+
+ /* Enable the required output lines */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
+ SUN4I_I2S_CTRL_SDO_EN(lines));
+
+ i2s->variant->set_txchanmap(i2s, 0, 0x10);
+ i2s->variant->set_txchansel(i2s, 0, channels > 1 ? 2 : 1);
+
+ if (i2s->variant->set_txchanen)
+ i2s->variant->set_txchanen(i2s, 0, 2);
+
+ if (i2s->variant->set_txchanoffset) {
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
+
+ if (channels > 2) {
+ i2s->variant->set_txchanmap(i2s, 1, 0x32);
+ i2s->variant->set_txchanoffset(i2s, 1);
+ i2s->variant->set_txchansel(i2s, 1,
+ channels > 3 ? 2 : 1);
+ i2s->variant->set_txchanen(i2s, 1, 2);
+ }
+ if (channels > 4) {
+ i2s->variant->set_txchanmap(i2s, 2, 0x54);
+ i2s->variant->set_txchanoffset(i2s, 2);
+ i2s->variant->set_txchansel(i2s, 2,
+ channels > 5 ? 2 : 1);
+ i2s->variant->set_txchanen(i2s, 2, 2);
+ }
+ if (channels > 6) {
+ i2s->variant->set_txchanmap(i2s, 3, 0x76);
+ i2s->variant->set_txchanoffset(i2s, 3);
+ i2s->variant->set_txchansel(i2s, 3,
+ channels > 6 ? 2 : 1);
+ i2s->variant->set_txchanen(i2s, 3, 2);
+ }
+ }
+ } else {
+ if (channels > dai->driver->capture.channels_max ||
+ channels < dai->driver->capture.channels_min) {
+ dev_err(dai->dev, "Unsupported number of channels: %d\n",
+ channels);
+ return -EINVAL;
+ }
+
+ /* Map the channels for capture */
+ i2s->variant->set_rxchanmap(i2s, 0x10);
+ i2s->variant->set_rxchansel(i2s, channels);
+
+ if (i2s->variant->set_rxchanen)
+ i2s->variant->set_rxchanen(i2s, channels);
+
+ if (i2s->variant->set_rxchanoffset)
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
+ SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
+ }
+
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
+ case 32:
+ width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
default:
dev_err(dai->dev, "Unsupported physical sample width: %d\n",
params_physical_width(params));
@@ -516,7 +784,7 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
slots, slot_width);
}
-static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
+static int sun4i_i2s_set_soc_fmt(struct sun4i_i2s *i2s,
unsigned int fmt)
{
u32 val;
@@ -589,11 +857,10 @@ static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
return 0;
}
-static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
+static int sun8i_i2s_set_soc_fmt(struct sun4i_i2s *i2s,
unsigned int fmt)
{
u32 mode, val;
- u8 offset;
/*
* DAI clock polarity
@@ -632,27 +899,27 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
mode = SUN8I_I2S_CTRL_MODE_PCM;
- offset = 1;
+ i2s->offset = 1;
break;
case SND_SOC_DAIFMT_DSP_B:
mode = SUN8I_I2S_CTRL_MODE_PCM;
- offset = 0;
+ i2s->offset = 0;
break;
case SND_SOC_DAIFMT_I2S:
mode = SUN8I_I2S_CTRL_MODE_LEFT;
- offset = 1;
+ i2s->offset = 1;
break;
case SND_SOC_DAIFMT_LEFT_J:
mode = SUN8I_I2S_CTRL_MODE_LEFT;
- offset = 0;
+ i2s->offset = 0;
break;
case SND_SOC_DAIFMT_RIGHT_J:
mode = SUN8I_I2S_CTRL_MODE_RIGHT;
- offset = 0;
+ i2s->offset = 0;
break;
default:
@@ -661,12 +928,8 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
SUN8I_I2S_CTRL_MODE_MASK, mode);
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
+ i2s->variant->set_txchanoffset(i2s, 0);
+ i2s->variant->set_rxchanoffset(i2s);
/* DAI clock master masks */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -691,6 +954,22 @@ static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
return 0;
}
+static void sun4i_i2s_set_fmt_sext(const struct sun4i_i2s *i2s,
+ unsigned int sext)
+{
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+ SUN4I_I2S_FMT1_REG_SEXT_MASK,
+ SUN4I_I2S_FMT1_REG_SEXT(sext));
+}
+
+static void sun8i_i2s_set_fmt_sext(const struct sun4i_i2s *i2s,
+ unsigned int sext)
+{
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+ SUN8I_I2S_FMT1_REG_SEXT_MASK,
+ SUN8I_I2S_FMT1_REG_SEXT(sext));
+}
+
static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -717,9 +996,9 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
{
/* Flush RX FIFO */
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
- SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
- SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
+ regmap_write_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
+ SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
+ SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
/* Clear RX counter */
regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
@@ -738,9 +1017,9 @@ static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
{
/* Flush TX FIFO */
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
- SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
- SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
+ regmap_write_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
+ SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
+ SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
/* Clear TX counter */
regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);
@@ -862,6 +1141,10 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
static struct snd_soc_dai_driver sun4i_i2s_dai = {
.probe = sun4i_i2s_dai_probe,
.capture = {
@@ -869,14 +1152,14 @@ static struct snd_soc_dai_driver sun4i_i2s_dai = {
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SUN4I_FORMATS,
},
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SUN4I_FORMATS,
},
.ops = &sun4i_i2s_dai_ops,
.symmetric_rates = 1,
@@ -971,6 +1254,22 @@ static const struct reg_default sun8i_i2s_reg_defaults[] = {
{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
};
+static const struct reg_default sun50i_i2s_reg_defaults[] = {
+ { SUN4I_I2S_CTRL_REG, 0x00060000 },
+ { SUN4I_I2S_FMT0_REG, 0x00000033 },
+ { SUN4I_I2S_FMT1_REG, 0x00000030 },
+ { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
+ { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
+ { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
+ { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
+ { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
+ { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
+ { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
+};
+
static const struct regmap_config sun4i_i2s_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -998,6 +1297,19 @@ static const struct regmap_config sun8i_i2s_regmap_config = {
.volatile_reg = sun8i_i2s_volatile_reg,
};
+static const struct regmap_config sun50i_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN50I_H6_I2S_RX_CHAN_MAP1_REG,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = sun50i_i2s_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(sun50i_i2s_reg_defaults),
+ .writeable_reg = sun4i_i2s_wr_reg,
+ .readable_reg = sun8i_i2s_rd_reg,
+ .volatile_reg = sun8i_i2s_volatile_reg,
+};
+
static int sun4i_i2s_runtime_resume(struct device *dev)
{
struct sun4i_i2s *i2s = dev_get_drvdata(dev);
@@ -1077,6 +1389,11 @@ static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
.set_fmt = sun4i_i2s_set_soc_fmt,
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
+ .set_txchansel = sun4i_i2s_set_txchansel,
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
+ .set_txchanmap = sun4i_i2s_set_txchanmap,
+ .set_rxchanmap = sun4i_i2s_set_rxchanmap,
};
static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
@@ -1095,6 +1412,11 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
.set_fmt = sun4i_i2s_set_soc_fmt,
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
+ .set_txchansel = sun4i_i2s_set_txchansel,
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
+ .set_txchanmap = sun4i_i2s_set_txchanmap,
+ .set_rxchanmap = sun4i_i2s_set_rxchanmap,
};
/*
@@ -1118,6 +1440,9 @@ static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
.set_fmt = sun4i_i2s_set_soc_fmt,
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
+ .set_txchansel = sun4i_i2s_set_txchansel,
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
};
static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
@@ -1136,6 +1461,15 @@ static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
.get_wss = sun8i_i2s_get_sr_wss,
.set_chan_cfg = sun8i_i2s_set_chan_cfg,
.set_fmt = sun8i_i2s_set_soc_fmt,
+ .set_fmt_sext = sun8i_i2s_set_fmt_sext,
+ .set_txchanoffset = sun8i_i2s_set_txchanoffset,
+ .set_rxchanoffset = sun8i_i2s_set_rxchanoffset,
+ .set_txchanen = sun8i_i2s_set_txchanen,
+ .set_rxchanen = sun8i_i2s_set_rxchanen,
+ .set_txchansel = sun8i_i2s_set_txchansel,
+ .set_rxchansel = sun8i_i2s_set_rxchansel,
+ .set_txchanmap = sun8i_i2s_set_txchanmap,
+ .set_rxchanmap = sun8i_i2s_set_rxchanmap,
};
static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
@@ -1154,6 +1488,38 @@ static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
.get_wss = sun4i_i2s_get_wss,
.set_chan_cfg = sun4i_i2s_set_chan_cfg,
.set_fmt = sun4i_i2s_set_soc_fmt,
+ .set_fmt_sext = sun4i_i2s_set_fmt_sext,
+ .set_txchansel = sun4i_i2s_set_txchansel,
+ .set_rxchansel = sun4i_i2s_set_rxchansel,
+ .set_txchanmap = sun4i_i2s_set_txchanmap,
+ .set_rxchanmap = sun4i_i2s_set_rxchanmap,
+};
+
+static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
+ .has_reset = true,
+ .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG,
+ .sun4i_i2s_regmap = &sun50i_i2s_regmap_config,
+ .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
+ .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
+ .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
+ .bclk_dividers = sun8i_i2s_clk_div,
+ .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
+ .mclk_dividers = sun8i_i2s_clk_div,
+ .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div),
+ .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate,
+ .get_sr = sun8i_i2s_get_sr_wss,
+ .get_wss = sun8i_i2s_get_sr_wss,
+ .set_chan_cfg = sun8i_i2s_set_chan_cfg,
+ .set_fmt = sun8i_i2s_set_soc_fmt,
+ .set_fmt_sext = sun8i_i2s_set_fmt_sext,
+ .set_txchanoffset = sun50i_h6_i2s_set_txchanoffset,
+ .set_rxchanoffset = sun50i_h6_i2s_set_rxchanoffset,
+ .set_txchanen = sun50i_h6_i2s_set_txchanen,
+ .set_rxchanen = sun50i_h6_i2s_set_rxchanen,
+ .set_txchansel = sun50i_h6_i2s_set_txchansel,
+ .set_rxchansel = sun50i_h6_i2s_set_rxchansel,
+ .set_txchanmap = sun50i_h6_i2s_set_txchanmap,
+ .set_rxchanmap = sun50i_h6_i2s_set_rxchanmap,
};
static int sun4i_i2s_init_regmap_fields(struct device *dev,
@@ -1325,6 +1691,10 @@ static const struct of_device_id sun4i_i2s_match[] = {
.compatible = "allwinner,sun50i-a64-codec-i2s",
.data = &sun50i_a64_codec_i2s_quirks,
},
+ {
+ .compatible = "allwinner,sun50i-h6-i2s",
+ .data = &sun50i_h6_i2s_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
--
2.23.0
From 2da43795f6191505b2dd6e30938c3af4c90bf745 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 7 Nov 2019 07:36:11 +0100
Subject: [PATCH] sound: soc: sun4i-i2s: Fix rate calculation
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
sound/soc/sunxi/sun4i-i2s.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index d0a8d5810c0a..6c4241cb6509 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -334,6 +334,9 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
return -EINVAL;
}
+ if (i2s->slot_width)
+ slot_width = i2s->slot_width;
+
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
rate, slots, slot_width);
--
2.24.0

View File

@ -0,0 +1,134 @@
From aec30a56043a890b75440bb8c9673a07166cf104 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
Date: Fri, 30 Oct 2020 15:46:37 +0100
Subject: [PATCH 05/44] ASoC: sun4i-i2s: Change get_sr() and get_wss() to be
more explicit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We are actually using a complex formula to just return a bunch of
simple values. Also this formula is wrong for sun4i when calling
get_wss() the function return 4 instead of 3.
Replace this with a simpler switch case.
Also drop the i2s params which is unused and return a simple int as
returning an error code could be out of range for an s8 and there is
no optim to return a s8 here.
Fixes: 619c15f7fac9 ("ASoC: sun4i-i2s: Change SR and WSS computation")
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-5-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 75 +++++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 28 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -175,8 +175,8 @@ struct sun4i_i2s_quirks {
unsigned int num_mclk_dividers;
unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
- s8 (*get_sr)(const struct sun4i_i2s *, int);
- s8 (*get_wss)(const struct sun4i_i2s *, int);
+ int (*get_sr)(unsigned int width);
+ int (*get_wss)(unsigned int width);
/*
* In the set_chan_cfg() function pointer:
@@ -387,37 +387,56 @@ static int sun4i_i2s_set_clk_rate(struct
return 0;
}
-static s8 sun4i_i2s_get_sr(const struct sun4i_i2s *i2s, int width)
+static int sun4i_i2s_get_sr(unsigned int width)
{
- if (width < 16 || width > 24)
- return -EINVAL;
-
- if (width % 4)
- return -EINVAL;
+ switch (width) {
+ case 16:
+ return 0;
+ case 20:
+ return 1;
+ case 24:
+ return 2;
+ }
- return (width - 16) / 4;
+ return -EINVAL;
}
-static s8 sun4i_i2s_get_wss(const struct sun4i_i2s *i2s, int width)
+static int sun4i_i2s_get_wss(unsigned int width)
{
- if (width < 16 || width > 32)
- return -EINVAL;
-
- if (width % 4)
- return -EINVAL;
+ switch (width) {
+ case 16:
+ return 0;
+ case 20:
+ return 1;
+ case 24:
+ return 2;
+ case 32:
+ return 3;
+ }
- return (width - 16) / 4;
+ return -EINVAL;
}
-static s8 sun8i_i2s_get_sr_wss(const struct sun4i_i2s *i2s, int width)
+static int sun8i_i2s_get_sr_wss(unsigned int width)
{
- if (width % 4)
- return -EINVAL;
-
- if (width < 8 || width > 32)
- return -EINVAL;
+ switch (width) {
+ case 8:
+ return 1;
+ case 12:
+ return 2;
+ case 16:
+ return 3;
+ case 20:
+ return 4;
+ case 24:
+ return 5;
+ case 28:
+ return 6;
+ case 32:
+ return 7;
+ }
- return (width - 8) / 4 + 1;
+ return -EINVAL;
}
static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
@@ -582,11 +601,11 @@ static int sun4i_i2s_hw_params(struct sn
}
i2s->playback_dma_data.addr_width = width;
- sr = i2s->variant->get_sr(i2s, word_size);
+ sr = i2s->variant->get_sr(word_size);
if (sr < 0)
return -EINVAL;
- wss = i2s->variant->get_wss(i2s, slot_width);
+ wss = i2s->variant->get_wss(slot_width);
if (wss < 0)
return -EINVAL;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
From fe1ae019879d51633d8dcd705117c70b701b77e9 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Fri, 30 Oct 2020 15:46:38 +0100
Subject: [PATCH 06/44] ASoC: sun4i-i2s: Set sign extend sample
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
On the newer SoCs such as the H3 and A64 this is set by default
to transfer a 0 after each sample in each slot. However the A10
and A20 SoCs that this driver was developed on had a default
setting where it padded the audio gain with zeros.
This isn't a problem while we have only support for 16bit audio
but with larger sample resolution rates in the pipeline then SEXT
bits should be cleared so that they also pad at the LSB. Without
this the audio gets distorted.
Set sign extend sample for all the sunxi generations even if they
are not affected. This will keep consistency and avoid relying on
default.
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-6-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -48,6 +48,9 @@
#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
#define SUN4I_I2S_FMT1_REG 0x08
+#define SUN4I_I2S_FMT1_REG_SEXT_MASK BIT(8)
+#define SUN4I_I2S_FMT1_REG_SEXT(sext) ((sext) << 8)
+
#define SUN4I_I2S_FIFO_TX_REG 0x0c
#define SUN4I_I2S_FIFO_RX_REG 0x10
@@ -105,6 +108,9 @@
#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7)
#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7)
+#define SUN8I_I2S_FMT1_REG_SEXT_MASK GENMASK(5, 4)
+#define SUN8I_I2S_FMT1_REG_SEXT(sext) ((sext) << 4)
+
#define SUN8I_I2S_INT_STA_REG 0x0c
#define SUN8I_I2S_FIFO_TX_REG 0x20
@@ -686,6 +692,7 @@ static int sun4i_i2s_set_soc_fmt(const s
}
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
SUN4I_I2S_CTRL_MODE_MASK, val);
+
return 0;
}
@@ -788,6 +795,11 @@ static int sun8i_i2s_set_soc_fmt(const s
SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
val);
+ /* Set sign extension to pad out LSB with 0 */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+ SUN8I_I2S_FMT1_REG_SEXT_MASK,
+ SUN8I_I2S_FMT1_REG_SEXT(0));
+
return 0;
}
@@ -890,6 +902,11 @@ static int sun50i_h6_i2s_set_soc_fmt(con
SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
val);
+ /* Set sign extension to pad out LSB with 0 */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
+ SUN8I_I2S_FMT1_REG_SEXT_MASK,
+ SUN8I_I2S_FMT1_REG_SEXT(0));
+
return 0;
}

View File

@ -0,0 +1,61 @@
From 9c2121fe514f12c830bceea7b33872fa67af3e97 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Fri, 30 Oct 2020 15:46:39 +0100
Subject: [PATCH 07/44] ASoC: sun4i-i2s: Add 20 and 24 bit support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Extend the functionality of the driver to include support of 20 and
24 bits per sample.
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-7-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -600,6 +600,9 @@ static int sun4i_i2s_hw_params(struct sn
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
+ case 32:
+ width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
default:
dev_err(dai->dev, "Unsupported physical sample width: %d\n",
params_physical_width(params));
@@ -1081,6 +1084,10 @@ static int sun4i_i2s_dai_probe(struct sn
return 0;
}
+#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
static struct snd_soc_dai_driver sun4i_i2s_dai = {
.probe = sun4i_i2s_dai_probe,
.capture = {
@@ -1088,14 +1095,14 @@ static struct snd_soc_dai_driver sun4i_i
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SUN4I_FORMATS,
},
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_8000_192000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SUN4I_FORMATS,
},
.ops = &sun4i_i2s_dai_ops,
.symmetric_rates = 1,

View File

@ -0,0 +1,49 @@
From 9f0cbed8e957216d58a2dd5c9c8e795ec39004ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
Date: Fri, 30 Oct 2020 15:46:40 +0100
Subject: [PATCH 08/44] ASoC: sun4i-i2s: Fix sun8i volatile regs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The FIFO TX reg is volatile and sun8i i2s register
mapping is different from sun4i.
Even if in this case it's doesn't create an issue,
Avoid setting some regs that are undefined in sun8i.
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-8-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1162,12 +1162,19 @@ static bool sun8i_i2s_rd_reg(struct devi
static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
{
- if (reg == SUN8I_I2S_INT_STA_REG)
+ switch (reg) {
+ case SUN4I_I2S_FIFO_CTRL_REG:
+ case SUN4I_I2S_FIFO_RX_REG:
+ case SUN4I_I2S_FIFO_STA_REG:
+ case SUN4I_I2S_RX_CNT_REG:
+ case SUN4I_I2S_TX_CNT_REG:
+ case SUN8I_I2S_FIFO_TX_REG:
+ case SUN8I_I2S_INT_STA_REG:
return true;
- if (reg == SUN8I_I2S_FIFO_TX_REG)
- return false;
- return sun4i_i2s_volatile_reg(dev, reg);
+ default:
+ return false;
+ }
}
static const struct reg_default sun4i_i2s_reg_defaults[] = {

View File

@ -0,0 +1,53 @@
From de8ff7b3ac4736f5aa0c55968170bd449e46c88f Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Fri, 30 Oct 2020 15:46:41 +0100
Subject: [PATCH 09/44] ASoC: sun4i-i2s: Fix setting of FIFO modes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Because SUN4I_I2S_FIFO_CTRL_REG is volatile, writes done while the
regmap is cache-only are ignored. To work around this, move the
configuration to a callback that runs while the ASoC core has a
runtime PM reference to the device.
Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-9-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -596,6 +596,13 @@ static int sun4i_i2s_hw_params(struct sn
return ret;
}
+ /* Set significant bits in our FIFOs */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
+ SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
+ SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
+ SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
+ SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
+
switch (params_physical_width(params)) {
case 16:
width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -924,13 +931,6 @@ static int sun4i_i2s_set_fmt(struct snd_
return ret;
}
- /* Set significant bits in our FIFOs */
- regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
- SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
- SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
- SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
- SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
-
i2s->format = fmt;
return 0;

View File

@ -0,0 +1,44 @@
From 82b0eb24d554180fdea8a254553dcce22085cc74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= <peron.clem@gmail.com>
Date: Fri, 30 Oct 2020 15:46:42 +0100
Subject: [PATCH 10/44] ASoC: sun4i-i2s: fix coding-style for callback
definition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Checkpatch script produces warning:
WARNING: function definition argument 'const struct sun4i_i2s *'
should also have an identifier name.
Let's fix this by adding identifier name to get_bclk_parent_rate()
and set_fmt() callback definition.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Link: https://lore.kernel.org/r/20201030144648.397824-10-peron.clem@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
---
sound/soc/sunxi/sun4i-i2s.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -180,7 +180,7 @@ struct sun4i_i2s_quirks {
const struct sun4i_i2s_clk_div *mclk_dividers;
unsigned int num_mclk_dividers;
- unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *);
+ unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s);
int (*get_sr)(unsigned int width);
int (*get_wss)(unsigned int width);
@@ -192,7 +192,7 @@ struct sun4i_i2s_quirks {
int (*set_chan_cfg)(const struct sun4i_i2s *i2s,
unsigned int channels, unsigned int slots,
unsigned int slot_width);
- int (*set_fmt)(const struct sun4i_i2s *, unsigned int);
+ int (*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt);
};
struct sun4i_i2s {

View File

@ -1,8 +1,23 @@
diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index 7907569e7b5c..d5ad3b9efd12 100644
From 51ebc019df15b46d109bafe7068ebb6fe0b266b5 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 6 Jan 2021 19:19:01 +0100
Subject: [PATCH 11/44] ARM: dts: sun8i: r40: Add deinterlace node
R40 contains deinterlace core compatible to that in H3. One peculiarity
is that RAM gate is shared with CSI1. User manual states it's separate
but that's not true. Shared gate was verified with BSP Linux code check
and with runtime tests (CPU crashed if CSI1 gate was not ungated).
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Link: https://lore.kernel.org/r/20210106181901.1324075-3-jernej.skrabec@siol.net
---
arch/arm/boot/dts/sun8i-r40.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -190,6 +190,25 @@ mixer1_out_tcon_top: endpoint {
@@ -190,6 +190,25 @@
};
};

View File

@ -1,8 +1,22 @@
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
index 10489e508695..578a63dedf46 100644
From 7166a5b6ab1f3d9ba0f5236b738525e828138c8e Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 6 Jan 2021 19:25:23 +0100
Subject: [PATCH 12/44] arm64: dts: allwinner: h5: Add deinterlace node
Deinterlace core is completely compatible to H3.
Add a node for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Link: https://lore.kernel.org/r/20210106182523.1325796-1-jernej.skrabec@siol.net
---
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
@@ -121,6 +121,19 @@ crypto: crypto@1c15000 {
@@ -121,6 +121,19 @@
resets = <&ccu RST_BUS_CE>;
};

View File

@ -0,0 +1,40 @@
From dcd9635dc6027b04a64e19ebb3dc15aaae082400 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 18 Feb 2020 19:24:29 +0100
Subject: [PATCH 13/44] drm/sun4i: csc: Rework DE3 CSC macros
Rework DE3 CSC macros to take just one coordinate instead of two. This
will make its usage easier in subsequent commit.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 2 +-
drivers/gpu/drm/sun4i/sun8i_mixer.h | 6 ++----
2 files changed, 3 insertions(+), 5 deletions(-)
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -194,7 +194,7 @@ static void sun8i_de3_ccsc_set_coefficie
return;
}
- base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0, 0);
+ base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, base_reg, table, 12);
}
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -50,10 +50,8 @@
#define SUN8I_MIXER_BLEND_CK_MIN(base, x) ((base) + 0xe0 + 0x04 * (x))
#define SUN8I_MIXER_BLEND_OUTCTL(base) ((base) + 0xfc)
#define SUN50I_MIXER_BLEND_CSC_CTL(base) ((base) + 0x100)
-#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x, y) \
- ((base) + 0x110 + (layer) * 0x30 + (x) * 0x10 + 4 * (y))
-#define SUN50I_MIXER_BLEND_CSC_CONST(base, layer, i) \
- ((base) + 0x110 + (layer) * 0x30 + (i) * 0x10 + 0x0c)
+#define SUN50I_MIXER_BLEND_CSC_COEFF(base, layer, x) \
+ ((base) + 0x110 + (layer) * 0x30 + (x) * 4)
#define SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK GENMASK(12, 8)
#define SUN8I_MIXER_BLEND_PIPE_CTL_EN(pipe) BIT(8 + pipe)

View File

@ -0,0 +1,163 @@
From acdfa534d3fe6759f43c1fe0bcd2fd40f31d3797 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 18 Feb 2020 19:44:33 +0100
Subject: [PATCH 14/44] drm/sun4i: de2/de3: Remove redundant CSC matrices
YUV to RGB matrices are almost identical to YVU to RGB matrices. They
only have second and third column reversed. Do that reversion in code in
order to lower amount of static data and redundancy.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 99 +++++++++++--------------------
1 file changed, 34 insertions(+), 65 deletions(-)
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -46,33 +46,6 @@ static const u32 yuv2rgb[2][2][12] = {
},
};
-static const u32 yvu2rgb[2][2][12] = {
- [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
- [DRM_COLOR_YCBCR_BT601] = {
- 0x000004A8, 0x00000662, 0x00000000, 0xFFFC8451,
- 0x000004A8, 0xFFFFFCC0, 0xFFFFFE6F, 0x00021E4D,
- 0x000004A8, 0x00000000, 0x00000811, 0xFFFBACA9,
- },
- [DRM_COLOR_YCBCR_BT709] = {
- 0x000004A8, 0x0000072B, 0x00000000, 0xFFFC1F99,
- 0x000004A8, 0xFFFFFDDF, 0xFFFFFF26, 0x00013383,
- 0x000004A8, 0x00000000, 0x00000873, 0xFFFB7BEF,
- }
- },
- [DRM_COLOR_YCBCR_FULL_RANGE] = {
- [DRM_COLOR_YCBCR_BT601] = {
- 0x00000400, 0x0000059B, 0x00000000, 0xFFFD322E,
- 0x00000400, 0xFFFFFD25, 0xFFFFFEA0, 0x00021DD5,
- 0x00000400, 0x00000000, 0x00000716, 0xFFFC74BD,
- },
- [DRM_COLOR_YCBCR_BT709] = {
- 0x00000400, 0x0000064C, 0x00000000, 0xFFFCD9B4,
- 0x00000400, 0xFFFFFE21, 0xFFFFFF41, 0x00014F96,
- 0x00000400, 0x00000000, 0x0000076C, 0xFFFC49EF,
- }
- },
-};
-
/*
* DE3 has a bit different CSC units. Factors are in two's complement format.
* First three factors in a row are multiplication factors which have 17 bits
@@ -123,33 +96,6 @@ static const u32 yuv2rgb_de3[2][2][12] =
},
};
-static const u32 yvu2rgb_de3[2][2][12] = {
- [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
- [DRM_COLOR_YCBCR_BT601] = {
- 0x0002542A, 0x0003312A, 0x00000000, 0xFFC00000,
- 0x0002542A, 0xFFFE5FC3, 0xFFFF376B, 0xFE000000,
- 0x0002542A, 0x00000000, 0x000408D2, 0xFE000000,
- },
- [DRM_COLOR_YCBCR_BT709] = {
- 0x0002542A, 0x000395E2, 0x00000000, 0xFFC00000,
- 0x0002542A, 0xFFFEEF27, 0xFFFF92D2, 0xFE000000,
- 0x0002542A, 0x00000000, 0x0004398C, 0xFE000000,
- }
- },
- [DRM_COLOR_YCBCR_FULL_RANGE] = {
- [DRM_COLOR_YCBCR_BT601] = {
- 0x00020000, 0x0002CDD2, 0x00000000, 0x00000000,
- 0x00020000, 0xFFFE925D, 0xFFFF4FCE, 0xFE000000,
- 0x00020000, 0x00000000, 0x00038B43, 0xFE000000,
- },
- [DRM_COLOR_YCBCR_BT709] = {
- 0x00020000, 0x0003264C, 0x00000000, 0x00000000,
- 0x00020000, 0xFFFF1053, 0xFFFFA018, 0xFE000000,
- 0x00020000, 0x00000000, 0x0003B611, 0xFE000000,
- }
- },
-};
-
static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
enum sun8i_csc_mode mode,
enum drm_color_encoding encoding,
@@ -157,21 +103,30 @@ static void sun8i_csc_set_coefficients(s
{
const u32 *table;
u32 base_reg;
+ int i;
+
+ table = yuv2rgb[range][encoding];
switch (mode) {
case SUN8I_CSC_MODE_YUV2RGB:
- table = yuv2rgb[range][encoding];
+ base_reg = SUN8I_CSC_COEFF(base, 0);
+ regmap_bulk_write(map, base_reg, table, 12);
break;
case SUN8I_CSC_MODE_YVU2RGB:
- table = yvu2rgb[range][encoding];
+ for (i = 0; i < 12; i++) {
+ if ((i & 3) == 1)
+ base_reg = SUN8I_CSC_COEFF(base, i + 1);
+ else if ((i & 3) == 2)
+ base_reg = SUN8I_CSC_COEFF(base, i - 1);
+ else
+ base_reg = SUN8I_CSC_COEFF(base, i);
+ regmap_write(map, base_reg, table[i]);
+ }
break;
default:
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
-
- base_reg = SUN8I_CSC_COEFF(base, 0);
- regmap_bulk_write(map, base_reg, table, 12);
}
static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
@@ -180,22 +135,36 @@ static void sun8i_de3_ccsc_set_coefficie
enum drm_color_range range)
{
const u32 *table;
- u32 base_reg;
+ u32 addr;
+ int i;
+
+ table = yuv2rgb_de3[range][encoding];
switch (mode) {
case SUN8I_CSC_MODE_YUV2RGB:
- table = yuv2rgb_de3[range][encoding];
+ addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
+ regmap_bulk_write(map, addr, table, 12);
break;
case SUN8I_CSC_MODE_YVU2RGB:
- table = yvu2rgb_de3[range][encoding];
+ for (i = 0; i < 12; i++) {
+ if ((i & 3) == 1)
+ addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
+ layer,
+ i + 1);
+ else if ((i & 3) == 2)
+ addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
+ layer,
+ i - 1);
+ else
+ addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
+ layer, i);
+ regmap_write(map, addr, table[i]);
+ }
break;
default:
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
-
- base_reg = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
- regmap_bulk_write(map, base_reg, table, 12);
}
static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)

View File

@ -0,0 +1,62 @@
From 2c9a7a5a71d5ed6db9ee28a5ccd11f0db45f574d Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 15 Apr 2020 10:24:05 +0200
Subject: [PATCH 15/44] drm/sun4i: Add support for BT2020 to DE3
DE3 supports 10-bit formats, so it's only naturally to also support
BT2020 encoding.
Add support for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 12 +++++++++++-
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 2 ++
2 files changed, 13 insertions(+), 1 deletion(-)
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -69,7 +69,7 @@ static const u32 yuv2rgb[2][2][12] = {
* c20 c21 c22 [d2 const2]
*/
-static const u32 yuv2rgb_de3[2][2][12] = {
+static const u32 yuv2rgb_de3[2][3][12] = {
[DRM_COLOR_YCBCR_LIMITED_RANGE] = {
[DRM_COLOR_YCBCR_BT601] = {
0x0002542A, 0x00000000, 0x0003312A, 0xFFC00000,
@@ -80,6 +80,11 @@ static const u32 yuv2rgb_de3[2][2][12] =
0x0002542A, 0x00000000, 0x000395E2, 0xFFC00000,
0x0002542A, 0xFFFF92D2, 0xFFFEEF27, 0xFE000000,
0x0002542A, 0x0004398C, 0x00000000, 0xFE000000,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x0002542A, 0x00000000, 0x00035B7B, 0xFFC00000,
+ 0x0002542A, 0xFFFFA017, 0xFFFEB2FC, 0xFE000000,
+ 0x0002542A, 0x00044896, 0x00000000, 0xFE000000,
}
},
[DRM_COLOR_YCBCR_FULL_RANGE] = {
@@ -92,6 +97,11 @@ static const u32 yuv2rgb_de3[2][2][12] =
0x00020000, 0x00000000, 0x0003264C, 0x00000000,
0x00020000, 0xFFFFA018, 0xFFFF1053, 0xFE000000,
0x00020000, 0x0003B611, 0x00000000, 0xFE000000,
+ },
+ [DRM_COLOR_YCBCR_BT2020] = {
+ 0x00020000, 0x00000000, 0x0002F2FE, 0x00000000,
+ 0x00020000, 0xFFFFABC0, 0xFFFEDB78, 0xFE000000,
+ 0x00020000, 0x0003C346, 0x00000000, 0xFE000000,
}
},
};
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -543,6 +543,8 @@ struct sun8i_vi_layer *sun8i_vi_layer_in
supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
BIT(DRM_COLOR_YCBCR_BT709);
+ if (mixer->cfg->is_de3)
+ supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
BIT(DRM_COLOR_YCBCR_FULL_RANGE);

View File

@ -0,0 +1,27 @@
From e689f3536e632e26166e66eac88728c6653a18b6 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Tue, 12 Jan 2021 23:24:21 -0600
Subject: [PATCH 16/44] mmc: sunxi-mmc: Ensure host is suspended during system
sleep
If the device suspend process begins before the mmc host's autosuspend
timeout, the host will continue running during system sleep. Avoid
this by forcing runtime suspend during a global suspend transition.
Signed-off-by: Samuel Holland <samuel@sholland.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
---
drivers/mmc/host/sunxi-mmc.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -1506,6 +1506,8 @@ static int sunxi_mmc_runtime_suspend(str
#endif
static const struct dev_pm_ops sunxi_mmc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(sunxi_mmc_runtime_suspend,
sunxi_mmc_runtime_resume,
NULL)

View File

@ -0,0 +1,42 @@
From e019a54d084020e6acc2869da341b376700bfe4c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 30 Oct 2020 15:46:44 +0100
Subject: [PATCH 17/44] arm64: dts: allwinner: h6: Add I2S1 node
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add Allwinner H6 I2S1 node connected to HDMI interface.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Link: https://lore.kernel.org/r/20201030144648.397824-12-peron.clem@gmail.com
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -609,6 +609,19 @@
};
};
+ i2s1: i2s@5091000 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-h6-i2s";
+ reg = <0x05091000 0x1000>;
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S1>, <&ccu CLK_I2S1>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 4>, <&dma 4>;
+ resets = <&ccu RST_BUS_I2S1>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
spdif: spdif@5093000 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun50i-h6-spdif";

View File

@ -0,0 +1,43 @@
From 0175a3d5680924d3d64ee8181b50c8b06ee715d1 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Fri, 30 Oct 2020 15:46:45 +0100
Subject: [PATCH 18/44] arm64: dts: allwinner: a64: Add I2S2 node
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add the I2S2 node connected to the HDMI interface.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Link: https://lore.kernel.org/r/20201030144648.397824-13-peron.clem@gmail.com
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -846,6 +846,20 @@
status = "disabled";
};
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun50i-a64-i2s",
+ "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "rx", "tx";
+ dmas = <&dma 27>, <&dma 27>;
+ status = "disabled";
+ };
+
dai: dai@1c22c00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun50i-a64-codec-i2s";

View File

@ -0,0 +1,42 @@
From fd67e65487b4e5e2a93df2868043302a99f93098 Mon Sep 17 00:00:00 2001
From: Marcus Cooper <codekipper@gmail.com>
Date: Fri, 30 Oct 2020 15:46:48 +0100
Subject: [PATCH 19/44] arm: dts: sunxi: h3/h5: Add I2S2 node
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add H3/H5 I2S2 node connected to the HDMI interface.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Signed-off-by: Clément Péron <peron.clem@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Link: https://lore.kernel.org/r/20201030144648.397824-16-peron.clem@gmail.com
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 13 +++++++++++++
1 file changed, 13 insertions(+)
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -662,6 +662,19 @@
status = "disabled";
};
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 27>;
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "tx";
+ status = "disabled";
+ };
+
codec: codec@1c22c00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun8i-h3-codec";

View File

@ -0,0 +1,47 @@
From 3c970c9e87e403b190407dec5c6e4745aef78e6a Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 30 Oct 2020 18:25:30 +0100
Subject: [PATCH 20/44] arm64: dts: allwinner: h6: PineH64 model B: Add wifi
PineH64 model B contains RTL8723CS wifi+bt combo module.
Since bluetooth support is not yet squared away, only wifi is enabled
for now.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Tested-by: <clabbe.montjoie@gmail.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Link: https://lore.kernel.org/r/20201030172530.1096394-1-jernej.skrabec@siol.net
---
.../dts/allwinner/sun50i-h6-pine-h64-model-b.dts | 15 +++++++++++++++
1 file changed, 15 insertions(+)
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64-model-b.dts
@@ -10,6 +10,12 @@
compatible = "pine64,pine-h64-model-b", "allwinner,sun50i-h6";
/delete-node/ reg_gmac_3v3;
+
+ wifi_pwrseq: wifi_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
+ post-power-on-delay-ms = <200>;
+ };
};
&hdmi_connector {
@@ -19,3 +25,12 @@
&emac {
phy-supply = <&reg_aldo2>;
};
+
+&mmc1 {
+ vmmc-supply = <&reg_cldo3>;
+ vqmmc-supply = <&reg_aldo1>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};

View File

@ -1,7 +1,7 @@
From 45e6e50e3420425d1db8022aa2773dd697c6f054 Mon Sep 17 00:00:00 2001
From 3a9d4fe5b89c783d2162c84db3cabf00c3bca983 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 23 Dec 2020 11:23:40 +0100
Subject: [PATCH 2/2] media: cedrus: Fix H264 decoding
Subject: [PATCH 21/44] media: cedrus: Fix H264 decoding
During H264 API overhaul subtle bug was introduced Cedrus driver.
Progressive references have both, top and bottom reference flags set.
@ -20,11 +20,9 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index 781c84a9b1b7..de7442d4834d 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -203,7 +203,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
@@ -203,7 +203,7 @@ static void _cedrus_write_ref_list(struc
position = cedrus_buf->codec.h264.position;
sram_array[i] |= position << 1;
@ -33,6 +31,3 @@ index 781c84a9b1b7..de7442d4834d 100644
sram_array[i] |= BIT(0);
}
--
2.29.2

View File

@ -1,17 +1,15 @@
From e7b2f400507263f12872db06f4cd69bc80f62c2f Mon Sep 17 00:00:00 2001
From 91b69779e0875e58d8973b2938a1cc4b7a1c455b Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Sun, 25 Mar 2018 22:17:06 +0200
Subject: [PATCH 10/15] ASoC: hdmi-codec: fix channel allocation
Subject: [PATCH 22/44] ASoC: hdmi-codec: fix channel allocation
---
sound/soc/codecs/hdmi-codec.c | 113 +++++++++++++++++++-----------------------
sound/soc/codecs/hdmi-codec.c | 113 ++++++++++++++++------------------
1 file changed, 52 insertions(+), 61 deletions(-)
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index bfb1519..47632a3 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -202,78 +202,69 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
@@ -195,78 +195,69 @@ static const struct snd_pcm_chmap_elem h
*/
static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
{ .ca_id = 0x00, .n_ch = 2,
@ -142,6 +140,3 @@ index bfb1519..47632a3 100644
};
struct hdmi_codec_priv {
--
2.14.1

View File

@ -0,0 +1,85 @@
From 82a8ceccbaf9aa3d8cbc56d10e3905eec0d4ffb4 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 13:55:15 +0200
Subject: [PATCH 23/44] media: uapi: hevc: Add scaling matrix control
HEVC has a scaling matrix concept. Add support for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 10 ++++++++++
include/media/hevc-ctrls.h | 11 +++++++++++
2 files changed, 21 insertions(+)
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1021,6 +1021,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set";
case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set";
case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters";
+ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix";
case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode";
case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code";
@@ -1461,6 +1462,9 @@ void v4l2_ctrl_fill(u32 id, const char *
case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
*type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX:
+ *type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX;
+ break;
case V4L2_CID_UNIT_CELL_SIZE:
*type = V4L2_CTRL_TYPE_AREA;
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -1934,6 +1938,9 @@ static int std_validate_compound(const s
zero_padding(*p_hevc_slice_params);
break;
+ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+ break;
+
case V4L2_CTRL_TYPE_AREA:
area = p;
if (!area->width || !area->height)
@@ -2626,6 +2633,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(s
case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
break;
+ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+ elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
+ break;
case V4L2_CTRL_TYPE_AREA:
elem_size = sizeof(struct v4l2_area);
break;
--- a/include/media/hevc-ctrls.h
+++ b/include/media/hevc-ctrls.h
@@ -19,6 +19,7 @@
#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008)
#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009)
#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010)
+#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (V4L2_CID_MPEG_BASE + 1011)
#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015)
#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016)
@@ -26,6 +27,7 @@
#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120
#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121
#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122
+#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123
enum v4l2_mpeg_video_hevc_decode_mode {
V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
@@ -209,4 +211,13 @@ struct v4l2_ctrl_hevc_slice_params {
__u64 flags;
};
+struct v4l2_ctrl_hevc_scaling_matrix {
+ __u8 scaling_list_4x4[6][16];
+ __u8 scaling_list_8x8[6][64];
+ __u8 scaling_list_16x16[6][64];
+ __u8 scaling_list_32x32[2][64];
+ __u8 scaling_list_dc_coef_16x16[6];
+ __u8 scaling_list_dc_coef_32x32[2];
+};
+
#endif

View File

@ -0,0 +1,150 @@
From b4b79b4eeacb63f0a72c866526e4a2021a201090 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 13:58:49 +0200
Subject: [PATCH 24/44] media: cedrus: hevc: Add support for scaling matrix
HEVC frames may use scaling list feature. Add support for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.c | 7 ++
drivers/staging/media/sunxi/cedrus/cedrus.h | 1 +
.../staging/media/sunxi/cedrus/cedrus_dec.c | 2 +
.../staging/media/sunxi/cedrus/cedrus_h265.c | 70 ++++++++++++++++++-
.../staging/media/sunxi/cedrus/cedrus_regs.h | 2 +
5 files changed, 81 insertions(+), 1 deletion(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -126,6 +126,13 @@ static const struct cedrus_control cedru
},
{
.cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
+ },
+ .codec = CEDRUS_CODEC_H265,
+ .required = true,
+ },
+ {
+ .cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
.max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
.def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -74,6 +74,7 @@ struct cedrus_h265_run {
const struct v4l2_ctrl_hevc_sps *sps;
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
+ const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
};
struct cedrus_run {
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -68,6 +68,8 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_HEVC_PPS);
run.h265.slice_params = cedrus_find_control_data(ctx,
V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
+ run.h265.scaling_matrix = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
break;
default:
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -238,6 +238,69 @@ static void cedrus_h265_skip_bits(struct
}
}
+static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_hevc_scaling_matrix *scaling;
+ struct cedrus_dev *dev = ctx->dev;
+ u32 i, j, k, val;
+
+ scaling = run->h265.scaling_matrix;
+
+ cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF0,
+ (scaling->scaling_list_dc_coef_32x32[1] << 24) |
+ (scaling->scaling_list_dc_coef_32x32[0] << 16) |
+ (scaling->scaling_list_dc_coef_16x16[1] << 8) |
+ (scaling->scaling_list_dc_coef_16x16[0] << 0));
+
+ cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF1,
+ (scaling->scaling_list_dc_coef_16x16[5] << 24) |
+ (scaling->scaling_list_dc_coef_16x16[4] << 16) |
+ (scaling->scaling_list_dc_coef_16x16[3] << 8) |
+ (scaling->scaling_list_dc_coef_16x16[2] << 0));
+
+ cedrus_h265_sram_write_offset(dev, VE_DEC_H265_SRAM_OFFSET_SCALING_LISTS);
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k += 4) {
+ val = ((u32)scaling->scaling_list_8x8[i][j + (k + 3) * 8] << 24) |
+ ((u32)scaling->scaling_list_8x8[i][j + (k + 2) * 8] << 16) |
+ ((u32)scaling->scaling_list_8x8[i][j + (k + 1) * 8] << 8) |
+ scaling->scaling_list_8x8[i][j + k * 8];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k += 4) {
+ val = ((u32)scaling->scaling_list_32x32[i][j + (k + 3) * 8] << 24) |
+ ((u32)scaling->scaling_list_32x32[i][j + (k + 2) * 8] << 16) |
+ ((u32)scaling->scaling_list_32x32[i][j + (k + 1) * 8] << 8) |
+ scaling->scaling_list_32x32[i][j + k * 8];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 8; j++)
+ for (k = 0; k < 8; k += 4) {
+ val = ((u32)scaling->scaling_list_16x16[i][j + (k + 3) * 8] << 24) |
+ ((u32)scaling->scaling_list_16x16[i][j + (k + 2) * 8] << 16) |
+ ((u32)scaling->scaling_list_16x16[i][j + (k + 1) * 8] << 8) |
+ scaling->scaling_list_16x16[i][j + k * 8];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 4; j++) {
+ val = ((u32)scaling->scaling_list_4x4[i][j + 12] << 24) |
+ ((u32)scaling->scaling_list_4x4[i][j + 8] << 16) |
+ ((u32)scaling->scaling_list_4x4[i][j + 4] << 8) |
+ scaling->scaling_list_4x4[i][j];
+ cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+ }
+}
+
static void cedrus_h265_setup(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
@@ -519,7 +582,12 @@ static void cedrus_h265_setup(struct ced
/* Scaling list. */
- reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT;
+ if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) {
+ cedrus_h265_write_scaling_list(ctx, run);
+ reg = VE_DEC_H265_SCALING_LIST_CTRL0_FLAG_ENABLED;
+ } else {
+ reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT;
+ }
cedrus_write(dev, VE_DEC_H265_SCALING_LIST_CTRL0, reg);
/* Neightbor information address. */
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -493,6 +493,8 @@
#define VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR (VE_ENGINE_DEC_H265 + 0x64)
#define VE_DEC_H265_TILE_START_CTB (VE_ENGINE_DEC_H265 + 0x68)
#define VE_DEC_H265_TILE_END_CTB (VE_ENGINE_DEC_H265 + 0x6c)
+#define VE_DEC_H265_SCALING_LIST_DC_COEF0 (VE_ENGINE_DEC_H265 + 0x78)
+#define VE_DEC_H265_SCALING_LIST_DC_COEF1 (VE_ENGINE_DEC_H265 + 0x7c)
#define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80)

View File

@ -0,0 +1,36 @@
From e61cf76fca5984dd9edcb0daf6c5cb5278f32e05 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 15:42:28 +0200
Subject: [PATCH 25/44] media: uapi: hevc: Add segment address field
If HEVC frame consists of multiple slices, segment address has to be
known in order to properly decode it.
Add segment address field to slice parameters.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
include/media/hevc-ctrls.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- a/include/media/hevc-ctrls.h
+++ b/include/media/hevc-ctrls.h
@@ -167,6 +167,9 @@ struct v4l2_ctrl_hevc_slice_params {
__u32 bit_size;
__u32 data_bit_offset;
+ /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
+ __u32 slice_segment_addr;
+
/* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
__u8 nal_unit_type;
__u8 nuh_temporal_id_plus1;
@@ -200,7 +203,7 @@ struct v4l2_ctrl_hevc_slice_params {
__u8 num_rps_poc_st_curr_after;
__u8 num_rps_poc_lt_curr;
- __u8 padding;
+ __u8 padding[5];
/* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];

View File

@ -0,0 +1,90 @@
From d99740197a9776b9332d21b9f3b05dab658a90eb Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 15:44:15 +0200
Subject: [PATCH 26/44] media: cedrus: hevc: Add support for multiple slices
Now that segment address is available, support for multi-slice frames
can be easily added.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../staging/media/sunxi/cedrus/cedrus_h265.c | 26 ++++++++++++-------
.../staging/media/sunxi/cedrus/cedrus_video.c | 1 +
2 files changed, 17 insertions(+), 10 deletions(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -309,6 +309,8 @@ static void cedrus_h265_setup(struct ced
const struct v4l2_ctrl_hevc_pps *pps;
const struct v4l2_ctrl_hevc_slice_params *slice_params;
const struct v4l2_hevc_pred_weight_table *pred_weight_table;
+ unsigned int width_in_ctb_luma, ctb_size_luma;
+ unsigned int log2_max_luma_coding_block_size;
dma_addr_t src_buf_addr;
dma_addr_t src_buf_end_addr;
u32 chroma_log2_weight_denom;
@@ -321,15 +323,17 @@ static void cedrus_h265_setup(struct ced
slice_params = run->h265.slice_params;
pred_weight_table = &slice_params->pred_weight_table;
+ log2_max_luma_coding_block_size =
+ sps->log2_min_luma_coding_block_size_minus3 + 3 +
+ sps->log2_diff_max_min_luma_coding_block_size;
+ ctb_size_luma = 1UL << log2_max_luma_coding_block_size;
+ width_in_ctb_luma =
+ DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma);
+
/* MV column buffer size and allocation. */
if (!ctx->codec.h265.mv_col_buf_size) {
unsigned int num_buffers =
run->dst->vb2_buf.vb2_queue->num_buffers;
- unsigned int log2_max_luma_coding_block_size =
- sps->log2_min_luma_coding_block_size_minus3 + 3 +
- sps->log2_diff_max_min_luma_coding_block_size;
- unsigned int ctb_size_luma =
- 1UL << log2_max_luma_coding_block_size;
/*
* Each CTB requires a MV col buffer with a specific unit size.
@@ -383,15 +387,17 @@ static void cedrus_h265_setup(struct ced
reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr);
cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg);
- /* Coding tree block address: start at the beginning. */
- reg = VE_DEC_H265_DEC_CTB_ADDR_X(0) | VE_DEC_H265_DEC_CTB_ADDR_Y(0);
+ /* Coding tree block address */
+ reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma);
+ reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma);
cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg);
cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
/* Clear the number of correctly-decoded coding tree blocks. */
- cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0);
+ if (ctx->fh.m2m_ctx->new_frame)
+ cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0);
/* Initialize bitstream access. */
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC);
@@ -543,8 +549,8 @@ static void cedrus_h265_setup(struct ced
V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT,
pps->flags);
- /* FIXME: For multi-slice support. */
- reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC;
+ if (ctx->fh.m2m_ctx->new_frame)
+ reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC;
cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO0, reg);
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -332,6 +332,7 @@ static int cedrus_s_fmt_vid_out(struct f
switch (ctx->src_fmt.pixelformat) {
case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_HEVC_SLICE:
vq->subsystem_flags |=
VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
break;

View File

@ -0,0 +1,195 @@
From 9e203d78974aa445086dbe6b667e49b3f00d36d0 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 26 Oct 2019 21:23:55 +0200
Subject: [PATCH 27/44] media: cedrus: hevc: tiles hack
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 2 +
.../staging/media/sunxi/cedrus/cedrus_h265.c | 93 +++++++++++++++++--
include/media/hevc-ctrls.h | 5 +-
3 files changed, 93 insertions(+), 7 deletions(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -135,6 +135,8 @@ struct cedrus_ctx {
ssize_t mv_col_buf_unit_size;
void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_addr;
+ void *entry_points_buf;
+ dma_addr_t entry_points_buf_addr;
} h265;
} codec;
};
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -301,6 +301,61 @@ static void cedrus_h265_write_scaling_li
}
}
+static void write_entry_point_list(struct cedrus_ctx *ctx,
+ struct cedrus_run *run,
+ unsigned int ctb_addr_x,
+ unsigned int ctb_addr_y)
+{
+ const struct v4l2_ctrl_hevc_slice_params *slice_params;
+ const struct v4l2_ctrl_hevc_pps *pps;
+ struct cedrus_dev *dev = ctx->dev;
+ int i, x, tx, y, ty;
+ u32 *entry_points;
+
+ pps = run->h265.pps;
+ slice_params = run->h265.slice_params;
+
+ for (x = 0, tx = 0; tx < pps->num_tile_columns_minus1 + 1; tx++) {
+ if (x + pps->column_width_minus1[tx] + 1 > ctb_addr_x)
+ break;
+
+ x += pps->column_width_minus1[tx] + 1;
+ }
+
+ for (y = 0, ty = 0; ty < pps->num_tile_rows_minus1 + 1; ty++) {
+ if (y + pps->row_height_minus1[ty] + 1 > ctb_addr_y)
+ break;
+
+ y += pps->row_height_minus1[ty] + 1;
+ }
+
+ cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, (y << 16) | (x << 0));
+ cedrus_write(dev, VE_DEC_H265_TILE_END_CTB,
+ ((y + pps->row_height_minus1[ty]) << 16) |
+ ((x + pps->column_width_minus1[tx]) << 0));
+
+ entry_points = ctx->codec.h265.entry_points_buf;
+ if (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) {
+ for (i = 0; i < slice_params->num_entry_point_offsets; i++)
+ entry_points[i] = slice_params->entry_point_offset_minus1[i] + 1;
+ } else {
+ for (i = 0; i < slice_params->num_entry_point_offsets; i++) {
+ if (tx + 1 >= pps->num_tile_columns_minus1 + 1) {
+ x = 0;
+ tx = 0;
+ y += pps->row_height_minus1[ty++] + 1;
+ } else {
+ x += pps->column_width_minus1[tx++] + 1;
+ }
+
+ entry_points[i * 4 + 0] = slice_params->entry_point_offset_minus1[i] + 1;
+ entry_points[i * 4 + 1] = 0x0;
+ entry_points[i * 4 + 2] = (y << 16) | (x << 0);
+ entry_points[i * 4 + 3] = ((y + pps->row_height_minus1[ty]) << 16) | ((x + pps->column_width_minus1[tx]) << 0);
+ }
+ }
+}
+
static void cedrus_h265_setup(struct cedrus_ctx *ctx,
struct cedrus_run *run)
{
@@ -311,6 +366,7 @@ static void cedrus_h265_setup(struct ced
const struct v4l2_hevc_pred_weight_table *pred_weight_table;
unsigned int width_in_ctb_luma, ctb_size_luma;
unsigned int log2_max_luma_coding_block_size;
+ unsigned int ctb_addr_x, ctb_addr_y;
dma_addr_t src_buf_addr;
dma_addr_t src_buf_end_addr;
u32 chroma_log2_weight_denom;
@@ -388,12 +444,19 @@ static void cedrus_h265_setup(struct ced
cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg);
/* Coding tree block address */
- reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma);
- reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma);
+ ctb_addr_x = slice_params->slice_segment_addr % width_in_ctb_luma;
+ ctb_addr_y = slice_params->slice_segment_addr / width_in_ctb_luma;
+ reg = VE_DEC_H265_DEC_CTB_ADDR_X(ctb_addr_x);
+ reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(ctb_addr_y);
cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg);
- cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
- cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
+ if ((pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) ||
+ (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED)) {
+ write_entry_point_list(ctx, run, ctb_addr_x, ctb_addr_y);
+ } else {
+ cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
+ cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
+ }
/* Clear the number of correctly-decoded coding tree blocks. */
if (ctx->fh.m2m_ctx->new_frame)
@@ -497,7 +560,9 @@ static void cedrus_h265_setup(struct ced
V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED,
pps->flags);
- /* TODO: VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED */
+ reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED,
+ V4L2_HEVC_PPS_FLAG_TILES_ENABLED,
+ pps->flags);
reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TRANSQUANT_BYPASS_ENABLED,
V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED,
@@ -573,12 +638,14 @@ static void cedrus_h265_setup(struct ced
chroma_log2_weight_denom = pred_weight_table->luma_log2_weight_denom +
pred_weight_table->delta_chroma_log2_weight_denom;
- reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(0) |
+ reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(slice_params->num_entry_point_offsets) |
VE_DEC_H265_DEC_SLICE_HDR_INFO2_CHROMA_LOG2_WEIGHT_DENOM(chroma_log2_weight_denom) |
VE_DEC_H265_DEC_SLICE_HDR_INFO2_LUMA_LOG2_WEIGHT_DENOM(pred_weight_table->luma_log2_weight_denom);
cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO2, reg);
+ cedrus_write(dev, VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR, ctx->codec.h265.entry_points_buf_addr >> 8);
+
/* Decoded picture size. */
reg = VE_DEC_H265_DEC_PIC_SIZE_WIDTH(ctx->src_fmt.width) |
@@ -672,6 +739,17 @@ static int cedrus_h265_start(struct cedr
if (!ctx->codec.h265.neighbor_info_buf)
return -ENOMEM;
+ ctx->codec.h265.entry_points_buf =
+ dma_alloc_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE,
+ &ctx->codec.h265.entry_points_buf_addr,
+ GFP_KERNEL);
+ if (!ctx->codec.h265.entry_points_buf) {
+ dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
+ ctx->codec.h265.neighbor_info_buf,
+ ctx->codec.h265.neighbor_info_buf_addr);
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -690,6 +768,9 @@ static void cedrus_h265_stop(struct cedr
dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h265.neighbor_info_buf,
ctx->codec.h265.neighbor_info_buf_addr);
+ dma_free_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE,
+ ctx->codec.h265.entry_points_buf,
+ ctx->codec.h265.entry_points_buf_addr);
}
static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
--- a/include/media/hevc-ctrls.h
+++ b/include/media/hevc-ctrls.h
@@ -169,6 +169,7 @@ struct v4l2_ctrl_hevc_slice_params {
/* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
__u32 slice_segment_addr;
+ __u32 num_entry_point_offsets;
/* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
__u8 nal_unit_type;
@@ -203,7 +204,9 @@ struct v4l2_ctrl_hevc_slice_params {
__u8 num_rps_poc_st_curr_after;
__u8 num_rps_poc_lt_curr;
- __u8 padding[5];
+ __u8 padding;
+
+ __u32 entry_point_offset_minus1[256];
/* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];

View File

@ -0,0 +1,50 @@
From b6d288bb8823e11114297d1e406ccd977106aaf9 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 13:06:15 +0100
Subject: [PATCH 28/44] media: cedrus: Add callback for buffer cleanup
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 1 +
drivers/staging/media/sunxi/cedrus/cedrus_video.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -149,6 +149,7 @@ struct cedrus_dec_ops {
int (*start)(struct cedrus_ctx *ctx);
void (*stop)(struct cedrus_ctx *ctx);
void (*trigger)(struct cedrus_ctx *ctx);
+ void (*buf_cleanup)(struct cedrus_ctx *ctx, struct cedrus_buffer *buf);
};
struct cedrus_variant {
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -455,6 +455,18 @@ static int cedrus_buf_prepare(struct vb2
return 0;
}
+static void cedrus_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+ struct cedrus_dev *dev = ctx->dev;
+ struct cedrus_dec_ops *ops = dev->dec_ops[ctx->current_codec];
+
+ if (!V4L2_TYPE_IS_OUTPUT(vq->type) && ops->buf_cleanup)
+ ops->buf_cleanup(ctx,
+ vb2_to_cedrus_buffer(vq->bufs[vb->index]));
+}
+
static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
@@ -535,6 +547,7 @@ static void cedrus_buf_request_complete(
static struct vb2_ops cedrus_qops = {
.queue_setup = cedrus_queue_setup,
.buf_prepare = cedrus_buf_prepare,
+ .buf_cleanup = cedrus_buf_cleanup,
.buf_queue = cedrus_buf_queue,
.buf_out_validate = cedrus_buf_out_validate,
.buf_request_complete = cedrus_buf_request_complete,

View File

@ -0,0 +1,235 @@
From d4ffac11f0d8b3a844f528e963b953a6bfe540af Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 13:22:05 +0100
Subject: [PATCH 29/44] media: cedrus: hevc: Improve buffer management
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 9 +-
.../staging/media/sunxi/cedrus/cedrus_h265.c | 117 ++++++++++--------
2 files changed, 69 insertions(+), 57 deletions(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -96,6 +96,11 @@ struct cedrus_buffer {
unsigned int position;
enum cedrus_h264_pic_type pic_type;
} h264;
+ struct {
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_size;
+ } h265;
} codec;
};
@@ -129,10 +134,6 @@ struct cedrus_ctx {
ssize_t intra_pred_buf_size;
} h264;
struct {
- void *mv_col_buf;
- dma_addr_t mv_col_buf_addr;
- ssize_t mv_col_buf_size;
- ssize_t mv_col_buf_unit_size;
void *neighbor_info_buf;
dma_addr_t neighbor_info_buf_addr;
void *entry_points_buf;
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -91,26 +91,66 @@ static void cedrus_h265_sram_write_data(
static inline dma_addr_t
cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx,
- unsigned int index, unsigned int field)
+ unsigned int index,
+ const struct v4l2_ctrl_hevc_sps *sps)
{
- return ctx->codec.h265.mv_col_buf_addr + index *
- ctx->codec.h265.mv_col_buf_unit_size +
- field * ctx->codec.h265.mv_col_buf_unit_size / 2;
+ struct cedrus_buffer *cedrus_buf = NULL;
+ struct vb2_buffer *buf = NULL;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (vq)
+ buf = vb2_get_buffer(vq, index);
+
+ if (buf)
+ cedrus_buf = vb2_to_cedrus_buffer(buf);
+
+ if (!cedrus_buf)
+ return 0;
+
+ if (!cedrus_buf->codec.h265.mv_col_buf_size) {
+ unsigned int ctb_size_luma, width_in_ctb_luma;
+ unsigned int log2_max_luma_coding_block_size;
+
+ log2_max_luma_coding_block_size =
+ sps->log2_min_luma_coding_block_size_minus3 + 3 +
+ sps->log2_diff_max_min_luma_coding_block_size;
+ ctb_size_luma = 1 << log2_max_luma_coding_block_size;
+ width_in_ctb_luma = DIV_ROUND_UP(sps->pic_width_in_luma_samples,
+ ctb_size_luma);
+
+ cedrus_buf->codec.h265.mv_col_buf_size = ALIGN(width_in_ctb_luma *
+ DIV_ROUND_UP(sps->pic_height_in_luma_samples, ctb_size_luma) *
+ CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE, 1024);
+
+ cedrus_buf->codec.h265.mv_col_buf =
+ dma_alloc_coherent(ctx->dev->dev,
+ cedrus_buf->codec.h265.mv_col_buf_size,
+ &cedrus_buf->codec.h265.mv_col_buf_dma,
+ GFP_KERNEL);
+
+ if (!cedrus_buf->codec.h265.mv_col_buf) {
+ cedrus_buf->codec.h265.mv_col_buf_size = 0;
+ cedrus_buf->codec.h265.mv_col_buf_dma = 0;
+ }
+ }
+
+ return cedrus_buf->codec.h265.mv_col_buf_dma;
}
static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx,
unsigned int index,
bool field_pic,
u32 pic_order_cnt[],
- int buffer_index)
+ int buffer_index,
+ const struct v4l2_ctrl_hevc_sps *sps)
{
struct cedrus_dev *dev = ctx->dev;
dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 0);
dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 1);
dma_addr_t mv_col_buf_addr[2] = {
- cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, 0),
- cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index,
- field_pic ? 1 : 0)
+ cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, sps),
+ cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, sps)
};
u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO +
VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index;
@@ -134,7 +174,8 @@ static void cedrus_h265_frame_info_write
static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx,
const struct v4l2_hevc_dpb_entry *dpb,
- u8 num_active_dpb_entries)
+ u8 num_active_dpb_entries,
+ const struct v4l2_ctrl_hevc_sps *sps)
{
struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -149,7 +190,7 @@ static void cedrus_h265_frame_info_write
cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic,
pic_order_cnt,
- buffer_index);
+ buffer_index, sps);
}
}
@@ -386,36 +427,6 @@ static void cedrus_h265_setup(struct ced
width_in_ctb_luma =
DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma);
- /* MV column buffer size and allocation. */
- if (!ctx->codec.h265.mv_col_buf_size) {
- unsigned int num_buffers =
- run->dst->vb2_buf.vb2_queue->num_buffers;
-
- /*
- * Each CTB requires a MV col buffer with a specific unit size.
- * Since the address is given with missing lsb bits, 1 KiB is
- * added to each buffer to ensure proper alignment.
- */
- ctx->codec.h265.mv_col_buf_unit_size =
- DIV_ROUND_UP(ctx->src_fmt.width, ctb_size_luma) *
- DIV_ROUND_UP(ctx->src_fmt.height, ctb_size_luma) *
- CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE + SZ_1K;
-
- ctx->codec.h265.mv_col_buf_size = num_buffers *
- ctx->codec.h265.mv_col_buf_unit_size;
-
- ctx->codec.h265.mv_col_buf =
- dma_alloc_coherent(dev->dev,
- ctx->codec.h265.mv_col_buf_size,
- &ctx->codec.h265.mv_col_buf_addr,
- GFP_KERNEL);
- if (!ctx->codec.h265.mv_col_buf) {
- ctx->codec.h265.mv_col_buf_size = 0;
- // TODO: Abort the process here.
- return;
- }
- }
-
/* Activate H265 engine. */
cedrus_engine_enable(ctx, CEDRUS_CODEC_H265);
@@ -669,7 +680,7 @@ static void cedrus_h265_setup(struct ced
/* Write decoded picture buffer in pic list. */
cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb,
- slice_params->num_active_dpb_entries);
+ slice_params->num_active_dpb_entries, sps);
/* Output frame. */
@@ -680,7 +691,7 @@ static void cedrus_h265_setup(struct ced
cedrus_h265_frame_info_write_single(ctx, output_pic_list_index,
slice_params->pic_struct != 0,
pic_order_cnt,
- run->dst->vb2_buf.index);
+ run->dst->vb2_buf.index, sps);
cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index);
@@ -729,9 +740,6 @@ static int cedrus_h265_start(struct cedr
{
struct cedrus_dev *dev = ctx->dev;
- /* The buffer size is calculated at setup time. */
- ctx->codec.h265.mv_col_buf_size = 0;
-
ctx->codec.h265.neighbor_info_buf =
dma_alloc_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
&ctx->codec.h265.neighbor_info_buf_addr,
@@ -757,14 +765,6 @@ static void cedrus_h265_stop(struct cedr
{
struct cedrus_dev *dev = ctx->dev;
- if (ctx->codec.h265.mv_col_buf_size > 0) {
- dma_free_coherent(dev->dev, ctx->codec.h265.mv_col_buf_size,
- ctx->codec.h265.mv_col_buf,
- ctx->codec.h265.mv_col_buf_addr);
-
- ctx->codec.h265.mv_col_buf_size = 0;
- }
-
dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h265.neighbor_info_buf,
ctx->codec.h265.neighbor_info_buf_addr);
@@ -780,6 +780,16 @@ static void cedrus_h265_trigger(struct c
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE);
}
+static void cedrus_h265_buf_cleanup(struct cedrus_ctx *ctx,
+ struct cedrus_buffer *buf)
+{
+ if (buf->codec.h265.mv_col_buf_size)
+ dma_free_coherent(ctx->dev->dev,
+ buf->codec.h265.mv_col_buf_size,
+ buf->codec.h265.mv_col_buf,
+ buf->codec.h265.mv_col_buf_dma);
+}
+
struct cedrus_dec_ops cedrus_dec_ops_h265 = {
.irq_clear = cedrus_h265_irq_clear,
.irq_disable = cedrus_h265_irq_disable,
@@ -788,4 +798,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h26
.start = cedrus_h265_start,
.stop = cedrus_h265_stop,
.trigger = cedrus_h265_trigger,
+ .buf_cleanup = cedrus_h265_buf_cleanup,
};

View File

@ -0,0 +1,197 @@
From a881ce25cba8e45c6a86b5a680981c3b14b5b1e1 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 9 Nov 2019 14:12:42 +0100
Subject: [PATCH 30/44] media: cedrus: h264: Improve buffer management
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.h | 3 +
.../staging/media/sunxi/cedrus/cedrus_h264.c | 93 ++++++++-----------
2 files changed, 44 insertions(+), 52 deletions(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -95,6 +95,9 @@ struct cedrus_buffer {
struct {
unsigned int position;
enum cedrus_h264_pic_type pic_type;
+ void *mv_col_buf;
+ dma_addr_t mv_col_buf_dma;
+ ssize_t mv_col_buf_size;
} h264;
struct {
void *mv_col_buf;
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -55,16 +55,14 @@ static void cedrus_h264_write_sram(struc
}
static dma_addr_t cedrus_h264_mv_col_buf_addr(struct cedrus_ctx *ctx,
- unsigned int position,
+ struct cedrus_buffer *buf,
unsigned int field)
{
- dma_addr_t addr = ctx->codec.h264.mv_col_buf_dma;
+ dma_addr_t addr = buf->codec.h264.mv_col_buf_dma;
- /* Adjust for the position */
- addr += position * ctx->codec.h264.mv_col_buf_field_size * 2;
-
- /* Adjust for the field */
- addr += field * ctx->codec.h264.mv_col_buf_field_size;
+ /* Adjust for the field */
+ if (field)
+ addr += buf->codec.h264.mv_col_buf_size / 2;
return addr;
}
@@ -76,7 +74,6 @@ static void cedrus_fill_ref_pic(struct c
struct cedrus_h264_sram_ref_pic *pic)
{
struct vb2_buffer *vbuf = &buf->m2m_buf.vb.vb2_buf;
- unsigned int position = buf->codec.h264.position;
pic->top_field_order_cnt = cpu_to_le32(top_field_order_cnt);
pic->bottom_field_order_cnt = cpu_to_le32(bottom_field_order_cnt);
@@ -85,9 +82,9 @@ static void cedrus_fill_ref_pic(struct c
pic->luma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 0));
pic->chroma_ptr = cpu_to_le32(cedrus_buf_addr(vbuf, &ctx->dst_fmt, 1));
pic->mv_col_top_ptr =
- cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 0));
+ cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, buf, 0));
pic->mv_col_bot_ptr =
- cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, position, 1));
+ cpu_to_le32(cedrus_h264_mv_col_buf_addr(ctx, buf, 1));
}
static void cedrus_write_frame_list(struct cedrus_ctx *ctx,
@@ -146,6 +143,28 @@ static void cedrus_write_frame_list(stru
output_buf = vb2_to_cedrus_buffer(&run->dst->vb2_buf);
output_buf->codec.h264.position = position;
+ if (!output_buf->codec.h264.mv_col_buf_size) {
+ const struct v4l2_ctrl_h264_sps *sps = run->h264.sps;
+ unsigned int field_size;
+
+ field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
+ DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE))
+ field_size = field_size * 2;
+ if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY))
+ field_size = field_size * 2;
+
+ output_buf->codec.h264.mv_col_buf_size = field_size * 2;
+ output_buf->codec.h264.mv_col_buf =
+ dma_alloc_coherent(dev->dev,
+ output_buf->codec.h264.mv_col_buf_size,
+ &output_buf->codec.h264.mv_col_buf_dma,
+ GFP_KERNEL);
+
+ if (!output_buf->codec.h264.mv_col_buf)
+ output_buf->codec.h264.mv_col_buf_size = 0;
+ }
+
if (decode->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)
output_buf->codec.h264.pic_type = CEDRUS_H264_PIC_TYPE_FIELD;
else if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)
@@ -516,8 +535,6 @@ static int cedrus_h264_start(struct cedr
{
struct cedrus_dev *dev = ctx->dev;
unsigned int pic_info_size;
- unsigned int field_size;
- unsigned int mv_col_size;
int ret;
/* Formula for picture buffer size is taken from CedarX source. */
@@ -560,37 +577,6 @@ static int cedrus_h264_start(struct cedr
goto err_pic_buf;
}
- field_size = DIV_ROUND_UP(ctx->src_fmt.width, 16) *
- DIV_ROUND_UP(ctx->src_fmt.height, 16) * 16;
-
- /*
- * FIXME: This is actually conditional to
- * V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE not being set, we
- * might have to rework this if memory efficiency ever is
- * something we need to work on.
- */
- field_size = field_size * 2;
-
- /*
- * FIXME: This is actually conditional to
- * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY not being set, we might
- * have to rework this if memory efficiency ever is something
- * we need to work on.
- */
- field_size = field_size * 2;
- ctx->codec.h264.mv_col_buf_field_size = field_size;
-
- mv_col_size = field_size * 2 * CEDRUS_H264_FRAME_NUM;
- ctx->codec.h264.mv_col_buf_size = mv_col_size;
- ctx->codec.h264.mv_col_buf = dma_alloc_coherent(dev->dev,
- ctx->codec.h264.mv_col_buf_size,
- &ctx->codec.h264.mv_col_buf_dma,
- GFP_KERNEL);
- if (!ctx->codec.h264.mv_col_buf) {
- ret = -ENOMEM;
- goto err_neighbor_buf;
- }
-
if (ctx->src_fmt.width > 2048) {
/*
* Formulas for deblock and intra prediction buffer sizes
@@ -606,7 +592,7 @@ static int cedrus_h264_start(struct cedr
GFP_KERNEL);
if (!ctx->codec.h264.deblk_buf) {
ret = -ENOMEM;
- goto err_mv_col_buf;
+ goto err_neighbor_buf;
}
/*
@@ -633,11 +619,6 @@ err_deblk_buf:
ctx->codec.h264.deblk_buf,
ctx->codec.h264.deblk_buf_dma);
-err_mv_col_buf:
- dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
- ctx->codec.h264.mv_col_buf,
- ctx->codec.h264.mv_col_buf_dma);
-
err_neighbor_buf:
dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h264.neighbor_info_buf,
@@ -654,9 +635,6 @@ static void cedrus_h264_stop(struct cedr
{
struct cedrus_dev *dev = ctx->dev;
- dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size,
- ctx->codec.h264.mv_col_buf,
- ctx->codec.h264.mv_col_buf_dma);
dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE,
ctx->codec.h264.neighbor_info_buf,
ctx->codec.h264.neighbor_info_buf_dma);
@@ -681,6 +659,16 @@ static void cedrus_h264_trigger(struct c
VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE);
}
+static void cedrus_h264_buf_cleanup(struct cedrus_ctx *ctx,
+ struct cedrus_buffer *buf)
+{
+ if (buf->codec.h264.mv_col_buf_size)
+ dma_free_coherent(ctx->dev->dev,
+ buf->codec.h264.mv_col_buf_size,
+ buf->codec.h264.mv_col_buf,
+ buf->codec.h264.mv_col_buf_dma);
+}
+
struct cedrus_dec_ops cedrus_dec_ops_h264 = {
.irq_clear = cedrus_h264_irq_clear,
.irq_disable = cedrus_h264_irq_disable,
@@ -689,4 +677,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h26
.start = cedrus_h264_start,
.stop = cedrus_h264_stop,
.trigger = cedrus_h264_trigger,
+ .buf_cleanup = cedrus_h264_buf_cleanup,
};

View File

@ -0,0 +1,155 @@
From 54389b5956af51023b073a08eeb7a746a4a37119 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 15 Mar 2020 21:35:39 +0100
Subject: [PATCH 31/44] WIp: 10-bit HEVC support
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.c | 4 +--
.../staging/media/sunxi/cedrus/cedrus_h265.c | 12 ++++++++
.../staging/media/sunxi/cedrus/cedrus_regs.h | 4 +++
.../staging/media/sunxi/cedrus/cedrus_video.c | 30 +++++++++++++++----
.../staging/media/sunxi/cedrus/cedrus_video.h | 2 +-
5 files changed, 44 insertions(+), 8 deletions(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -301,7 +301,7 @@ static int cedrus_open(struct file *file
goto err_ctrls;
}
ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12;
- cedrus_prepare_format(&ctx->dst_fmt);
+ cedrus_prepare_format(&ctx->dst_fmt, 0);
ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE;
/*
* TILED_NV12 has more strict requirements, so copy the width and
@@ -309,7 +309,7 @@ static int cedrus_open(struct file *file
*/
ctx->src_fmt.width = ctx->dst_fmt.width;
ctx->src_fmt.height = ctx->dst_fmt.height;
- cedrus_prepare_format(&ctx->src_fmt);
+ cedrus_prepare_format(&ctx->src_fmt, 0);
v4l2_fh_add(&ctx->fh);
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -532,6 +532,18 @@ static void cedrus_h265_setup(struct ced
cedrus_write(dev, VE_DEC_H265_DEC_PCM_CTRL, reg);
+ if (sps->bit_depth_luma_minus8 == 2) {
+ unsigned int size;
+
+ size = ALIGN(ctx->src_fmt.width, 16) * ALIGN(ctx->src_fmt.height, 16);
+
+ reg = (size * 3) / 2;
+ cedrus_write(dev, VE_DEC_H265_OFFSET_ADDR_FIRST_OUT, reg);
+
+ reg = DIV_ROUND_UP(ctx->src_fmt.width, 4);
+ cedrus_write(dev, VE_DEC_H265_10BIT_CONFIGURE, ALIGN(reg, 32));
+ }
+
/* PPS. */
reg = VE_DEC_H265_DEC_PPS_CTRL0_PPS_CR_QP_OFFSET(pps->pps_cr_qp_offset) |
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -498,6 +498,10 @@
#define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80)
+#define VE_DEC_H265_OFFSET_ADDR_FIRST_OUT (VE_ENGINE_DEC_H265 + 0x84)
+#define VE_DEC_H265_OFFSET_ADDR_SECOND_OUT (VE_ENGINE_DEC_H265 + 0x88)
+#define VE_DEC_H265_10BIT_CONFIGURE (VE_ENGINE_DEC_H265 + 0x8c)
+
#define VE_DEC_H265_LOW_ADDR_PRIMARY_CHROMA(a) \
SHIFT_AND_MASK_BITS(a, 31, 24)
#define VE_DEC_H265_LOW_ADDR_SECONDARY_CHROMA(a) \
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -93,7 +93,7 @@ static struct cedrus_format *cedrus_find
return &cedrus_formats[i];
}
-void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt)
+void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt, int extended)
{
unsigned int width = pix_fmt->width;
unsigned int height = pix_fmt->height;
@@ -147,6 +147,17 @@ void cedrus_prepare_format(struct v4l2_p
break;
}
+ if (extended) {
+ unsigned int extra_size;
+
+ extra_size = DIV_ROUND_UP(pix_fmt->width, 4);
+ extra_size = ALIGN(extra_size, 32);
+ extra_size *= ALIGN(pix_fmt->height, 16) * 3;
+ extra_size /= 2;
+
+ sizeimage += extra_size;
+ }
+
pix_fmt->width = width;
pix_fmt->height = height;
@@ -239,17 +250,27 @@ static int cedrus_try_fmt_vid_cap(struct
struct cedrus_ctx *ctx = cedrus_file2ctx(file);
struct cedrus_dev *dev = ctx->dev;
struct v4l2_pix_format *pix_fmt = &f->fmt.pix;
+ const struct v4l2_ctrl_hevc_sps *sps;
struct cedrus_format *fmt =
cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST,
dev->capabilities);
+ int extended;
if (!fmt)
return -EINVAL;
+ sps = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+
+ /* The 10-bitHEVC decoder needs extra size on the output buffer. */
+ extended = ctx->src_fmt.pixelformat == V4L2_PIX_FMT_HEVC_SLICE &&
+ sps->bit_depth_luma_minus8 == 2;
+
pix_fmt->pixelformat = fmt->pixelformat;
pix_fmt->width = ctx->src_fmt.width;
pix_fmt->height = ctx->src_fmt.height;
- cedrus_prepare_format(pix_fmt);
+
+ pix_fmt->pixelformat = fmt->pixelformat;
+ cedrus_prepare_format(pix_fmt, extended);
return 0;
}
@@ -267,8 +288,7 @@ static int cedrus_try_fmt_vid_out(struct
if (!fmt)
return -EINVAL;
- pix_fmt->pixelformat = fmt->pixelformat;
- cedrus_prepare_format(pix_fmt);
+ cedrus_prepare_format(pix_fmt, 0);
return 0;
}
@@ -349,7 +369,7 @@ static int cedrus_s_fmt_vid_out(struct f
ctx->dst_fmt.quantization = f->fmt.pix.quantization;
ctx->dst_fmt.width = ctx->src_fmt.width;
ctx->dst_fmt.height = ctx->src_fmt.height;
- cedrus_prepare_format(&ctx->dst_fmt);
+ cedrus_prepare_format(&ctx->dst_fmt, 0);
return 0;
}
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h
@@ -26,6 +26,6 @@ extern const struct v4l2_ioctl_ops cedru
int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
-void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt);
+void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt, int extended);
#endif

View File

@ -0,0 +1,100 @@
From f26df66c4d6ea08a865a16df82af37035401254d Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 21 Jul 2020 21:53:27 +0200
Subject: [PATCH 32/44] media: cedrus: add check for H264 and HEVC limitations
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/cedrus.c | 49 ++++++++++++++++++++-
drivers/staging/media/sunxi/cedrus/cedrus.h | 1 +
2 files changed, 49 insertions(+), 1 deletion(-)
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -28,6 +28,50 @@
#include "cedrus_dec.h"
#include "cedrus_hw.h"
+static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_SPS) {
+ const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
+
+ if (sps->chroma_format_idc != 1)
+ /* Only 4:2:0 is supported */
+ return -EINVAL;
+ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+ /* Luma and chroma bit depth mismatch */
+ return -EINVAL;
+ if (sps->bit_depth_luma_minus8 != 0)
+ /* Only 8-bit is supported */
+ return -EINVAL;
+ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) {
+ const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
+ struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
+
+ if (sps->chroma_format_idc != 1)
+ /* Only 4:2:0 is supported */
+ return -EINVAL;
+
+ if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
+ /* Luma and chroma bit depth mismatch */
+ return -EINVAL;
+
+ if (ctx->dev->capabilities & CEDRUS_CAPABILITY_H265_10_DEC) {
+ if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2)
+ /* Only 8-bit and 10-bit are supported */
+ return -EINVAL;
+ } else {
+ if (sps->bit_depth_luma_minus8 != 0)
+ /* Only 8-bit is supported */
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops cedrus_ctrl_ops = {
+ .try_ctrl = cedrus_try_ctrl,
+};
+
static const struct cedrus_control cedrus_controls[] = {
{
.cfg = {
@@ -60,6 +104,7 @@ static const struct cedrus_control cedru
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_H264_SPS,
+ .ops = &cedrus_ctrl_ops,
},
.codec = CEDRUS_CODEC_H264,
.required = true,
@@ -106,6 +151,7 @@ static const struct cedrus_control cedru
{
.cfg = {
.id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
+ .ops = &cedrus_ctrl_ops,
},
.codec = CEDRUS_CODEC_H265,
.required = true,
@@ -534,7 +580,8 @@ static const struct cedrus_variant sun50
static const struct cedrus_variant sun50i_h6_cedrus_variant = {
.capabilities = CEDRUS_CAPABILITY_UNTILED |
- CEDRUS_CAPABILITY_H265_DEC,
+ CEDRUS_CAPABILITY_H265_DEC |
+ CEDRUS_CAPABILITY_H265_10_DEC,
.quirks = CEDRUS_QUIRK_NO_DMA_OFFSET,
.mod_rate = 600000000,
};
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -28,6 +28,7 @@
#define CEDRUS_CAPABILITY_UNTILED BIT(0)
#define CEDRUS_CAPABILITY_H265_DEC BIT(1)
+#define CEDRUS_CAPABILITY_H265_10_DEC BIT(2)
#define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0)

View File

@ -0,0 +1,985 @@
From 574ba48fa87225fbf3e39ffd2b11a6fb93cb6c98 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Wed, 20 May 2020 23:01:29 +0200
Subject: [PATCH 33/44] media: cedrus: Add support for VP8 decoding
VP8 in Cedrus shares same engine as H264.
Note that it seems necessary to call bitstream parsing functions,
to parse frame header, otherwise decoded image is garbage. This is
contrary to what is driver supposed to do. However, values are not
really used, so this might be acceptable. It's possible that bitstream
parsing functions set some internal VPU state, which is later necessary
for proper decoding. Biggest suspect is "VP8 probs update" trigger.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/staging/media/sunxi/cedrus/Makefile | 3 +-
drivers/staging/media/sunxi/cedrus/cedrus.c | 8 +
drivers/staging/media/sunxi/cedrus/cedrus.h | 15 +
.../staging/media/sunxi/cedrus/cedrus_dec.c | 5 +
.../staging/media/sunxi/cedrus/cedrus_hw.c | 1 +
.../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++
.../staging/media/sunxi/cedrus/cedrus_video.c | 9 +
.../staging/media/sunxi/cedrus/cedrus_vp8.c | 699 ++++++++++++++++++
8 files changed, 819 insertions(+), 1 deletion(-)
create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
--- a/drivers/staging/media/sunxi/cedrus/Makefile
+++ b/drivers/staging/media/sunxi/cedrus/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \
- cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o
+ cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o \
+ cedrus_vp8.o
--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
@@ -195,6 +195,13 @@ static const struct cedrus_control cedru
.codec = CEDRUS_CODEC_H265,
.required = false,
},
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER,
+ },
+ .codec = CEDRUS_CODEC_VP8,
+ .required = true,
+ },
};
#define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls)
@@ -446,6 +453,7 @@ static int cedrus_probe(struct platform_
dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2;
dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264;
dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265;
+ dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8;
mutex_init(&dev->dev_mutex);
--- a/drivers/staging/media/sunxi/cedrus/cedrus.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus.h
@@ -36,6 +36,7 @@ enum cedrus_codec {
CEDRUS_CODEC_MPEG2,
CEDRUS_CODEC_H264,
CEDRUS_CODEC_H265,
+ CEDRUS_CODEC_VP8,
CEDRUS_CODEC_LAST,
};
@@ -78,6 +79,10 @@ struct cedrus_h265_run {
const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix;
};
+struct cedrus_vp8_run {
+ const struct v4l2_ctrl_vp8_frame_header *slice_params;
+};
+
struct cedrus_run {
struct vb2_v4l2_buffer *src;
struct vb2_v4l2_buffer *dst;
@@ -86,6 +91,7 @@ struct cedrus_run {
struct cedrus_h264_run h264;
struct cedrus_mpeg2_run mpeg2;
struct cedrus_h265_run h265;
+ struct cedrus_vp8_run vp8;
};
};
@@ -143,6 +149,14 @@ struct cedrus_ctx {
void *entry_points_buf;
dma_addr_t entry_points_buf_addr;
} h265;
+ struct {
+ unsigned int last_frame_p_type;
+ unsigned int last_filter_type;
+ unsigned int last_sharpness_level;
+
+ u8 *entropy_probs_buf;
+ dma_addr_t entropy_probs_buf_dma;
+ } vp8;
} codec;
};
@@ -190,6 +204,7 @@ struct cedrus_dev {
extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2;
extern struct cedrus_dec_ops cedrus_dec_ops_h264;
extern struct cedrus_dec_ops cedrus_dec_ops_h265;
+extern struct cedrus_dec_ops cedrus_dec_ops_vp8;
static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
{
--- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c
@@ -72,6 +72,11 @@ void cedrus_device_run(void *priv)
V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ run.vp8.slice_params = cedrus_find_control_data(ctx,
+ V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER);
+ break;
+
default:
break;
}
--- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c
@@ -48,6 +48,7 @@ int cedrus_engine_enable(struct cedrus_c
break;
case CEDRUS_CODEC_H264:
+ case CEDRUS_CODEC_VP8:
reg |= VE_MODE_DEC_H264;
break;
--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h
@@ -552,6 +552,7 @@
#define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24)
#define VE_H264_CTRL 0x220
+#define VE_H264_CTRL_VP8 BIT(29)
#define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2)
#define VE_H264_CTRL_DECODE_ERR_INT BIT(1)
#define VE_H264_CTRL_SLICE_DECODE_INT BIT(0)
@@ -561,7 +562,12 @@
VE_H264_CTRL_SLICE_DECODE_INT)
#define VE_H264_TRIGGER_TYPE 0x224
+#define VE_H264_TRIGGER_TYPE_PROBABILITY(x) SHIFT_AND_MASK_BITS(x, 31, 24)
+#define VE_H264_TRIGGER_TYPE_BIN_LENS(x) SHIFT_AND_MASK_BITS((x) - 1, 18, 16)
#define VE_H264_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8)
+#define VE_H264_TRIGGER_TYPE_VP8_GET_BITS (15 << 0)
+#define VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF (14 << 0)
+#define VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE (10 << 0)
#define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0)
#define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0)
#define VE_H264_TRIGGER_TYPE_FLUSH_BITS (3 << 0)
@@ -571,6 +577,7 @@
#define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT
#define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT
#define VE_H264_STATUS_VLD_BUSY BIT(8)
+#define VE_H264_STATUS_VP8_UPPROB_BUSY BIT(17)
#define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK
@@ -589,10 +596,83 @@
#define VE_H264_OUTPUT_FRAME_IDX 0x24c
#define VE_H264_EXTRA_BUFFER1 0x250
#define VE_H264_EXTRA_BUFFER2 0x254
+#define VE_H264_MB_ADDR 0x260
+#define VE_H264_ERROR_CASE 0x2b8
#define VE_H264_BASIC_BITS 0x2dc
#define VE_AVC_SRAM_PORT_OFFSET 0x2e0
#define VE_AVC_SRAM_PORT_DATA 0x2e4
+#define VE_VP8_PPS 0x214
+#define VE_VP8_PPS_PIC_TYPE_P_FRAME BIT(31)
+#define VE_VP8_PPS_LAST_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 30, 28)
+#define VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME BIT(27)
+#define VE_VP8_PPS_ALTREF_SIGN_BIAS BIT(26)
+#define VE_VP8_PPS_GOLDEN_SIGN_BIAS BIT(25)
+#define VE_VP8_PPS_RELOAD_ENTROPY_PROBS BIT(24)
+#define VE_VP8_PPS_REFRESH_ENTROPY_PROBS BIT(23)
+#define VE_VP8_PPS_MB_NO_COEFF_SKIP BIT(22)
+#define VE_VP8_PPS_TOKEN_PARTITION(v) SHIFT_AND_MASK_BITS(v, 21, 20)
+#define VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE BIT(19)
+#define VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE BIT(18)
+#define VE_VP8_PPS_LOOP_FILTER_LEVEL(v) SHIFT_AND_MASK_BITS(v, 17, 12)
+#define VE_VP8_PPS_LOOP_FILTER_SIMPLE BIT(11)
+#define VE_VP8_PPS_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 10, 8)
+#define VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE BIT(7)
+#define VE_VP8_PPS_SEGMENTATION_ENABLE BIT(6)
+#define VE_VP8_PPS_MB_SEGMENT_ABS_DELTA BIT(5)
+#define VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP BIT(4)
+#define VE_VP8_PPS_FULL_PIXEL BIT(3)
+#define VE_VP8_PPS_BILINEAR_MC_FILTER BIT(2)
+#define VE_VP8_PPS_FILTER_TYPE_SIMPLE BIT(1)
+#define VE_VP8_PPS_LPF_DISABLE BIT(0)
+
+#define VE_VP8_QP_INDEX_DELTA 0x218
+#define VE_VP8_QP_INDEX_DELTA_UVAC(v) SHIFT_AND_MASK_BITS(v, 31, 27)
+#define VE_VP8_QP_INDEX_DELTA_UVDC(v) SHIFT_AND_MASK_BITS(v, 26, 22)
+#define VE_VP8_QP_INDEX_DELTA_Y2AC(v) SHIFT_AND_MASK_BITS(v, 21, 17)
+#define VE_VP8_QP_INDEX_DELTA_Y2DC(v) SHIFT_AND_MASK_BITS(v, 16, 12)
+#define VE_VP8_QP_INDEX_DELTA_Y1DC(v) SHIFT_AND_MASK_BITS(v, 11, 7)
+#define VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(v) SHIFT_AND_MASK_BITS(v, 6, 0)
+
+#define VE_VP8_PART_SIZE_OFFSET 0x21c
+#define VE_VP8_ENTROPY_PROBS_ADDR 0x250
+#define VE_VP8_FIRST_DATA_PART_LEN 0x254
+
+#define VE_VP8_FSIZE 0x258
+#define VE_VP8_FSIZE_WIDTH(w) \
+ SHIFT_AND_MASK_BITS(DIV_ROUND_UP(w, 16), 15, 8)
+#define VE_VP8_FSIZE_HEIGHT(h) \
+ SHIFT_AND_MASK_BITS(DIV_ROUND_UP(h, 16), 7, 0)
+
+#define VE_VP8_PICSIZE 0x25c
+#define VE_VP8_PICSIZE_WIDTH(w) SHIFT_AND_MASK_BITS(w, 27, 16)
+#define VE_VP8_PICSIZE_HEIGHT(h) SHIFT_AND_MASK_BITS(h, 11, 0)
+
+#define VE_VP8_REC_LUMA 0x2ac
+#define VE_VP8_FWD_LUMA 0x2b0
+#define VE_VP8_BWD_LUMA 0x2b4
+#define VE_VP8_REC_CHROMA 0x2d0
+#define VE_VP8_FWD_CHROMA 0x2d4
+#define VE_VP8_BWD_CHROMA 0x2d8
+#define VE_VP8_ALT_LUMA 0x2e8
+#define VE_VP8_ALT_CHROMA 0x2ec
+
+#define VE_VP8_SEGMENT_FEAT_MB_LV0 0x2f0
+#define VE_VP8_SEGMENT_FEAT_MB_LV1 0x2f4
+
+#define VE_VP8_SEGMENT3(v) SHIFT_AND_MASK_BITS(v, 31, 24)
+#define VE_VP8_SEGMENT2(v) SHIFT_AND_MASK_BITS(v, 23, 16)
+#define VE_VP8_SEGMENT1(v) SHIFT_AND_MASK_BITS(v, 15, 8)
+#define VE_VP8_SEGMENT0(v) SHIFT_AND_MASK_BITS(v, 7, 0)
+
+#define VE_VP8_REF_LF_DELTA 0x2f8
+#define VE_VP8_MODE_LF_DELTA 0x2fc
+
+#define VE_VP8_LF_DELTA3(v) SHIFT_AND_MASK_BITS(v, 30, 24)
+#define VE_VP8_LF_DELTA2(v) SHIFT_AND_MASK_BITS(v, 22, 16)
+#define VE_VP8_LF_DELTA1(v) SHIFT_AND_MASK_BITS(v, 14, 8)
+#define VE_VP8_LF_DELTA0(v) SHIFT_AND_MASK_BITS(v, 6, 0)
+
#define VE_ISP_INPUT_SIZE 0xa00
#define VE_ISP_INPUT_STRIDE 0xa04
#define VE_ISP_CTRL 0xa08
--- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c
@@ -49,6 +49,10 @@ static struct cedrus_format cedrus_forma
.capabilities = CEDRUS_CAPABILITY_H265_DEC,
},
{
+ .pixelformat = V4L2_PIX_FMT_VP8_FRAME,
+ .directions = CEDRUS_DECODE_SRC,
+ },
+ {
.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12,
.directions = CEDRUS_DECODE_DST,
},
@@ -110,6 +114,7 @@ void cedrus_prepare_format(struct v4l2_p
case V4L2_PIX_FMT_MPEG2_SLICE:
case V4L2_PIX_FMT_H264_SLICE:
case V4L2_PIX_FMT_HEVC_SLICE:
+ case V4L2_PIX_FMT_VP8_FRAME:
/* Zero bytes per line for encoded source. */
bytesperline = 0;
/* Choose some minimum size since this can't be 0 */
@@ -506,6 +511,10 @@ static int cedrus_start_streaming(struct
ctx->current_codec = CEDRUS_CODEC_H265;
break;
+ case V4L2_PIX_FMT_VP8_FRAME:
+ ctx->current_codec = CEDRUS_CODEC_VP8;
+ break;
+
default:
return -EINVAL;
}
--- /dev/null
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
@@ -0,0 +1,699 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Cedrus VPU driver
+ *
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cedrus.h"
+#include "cedrus_hw.h"
+#include "cedrus_regs.h"
+
+#define CEDRUS_ENTROPY_PROBS_SIZE 0x2400
+#define VP8_PROB_HALF 128
+
+static const u8 prob_table_init[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xB0, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xF1, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF9, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF4, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xF6, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xEF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xE1, 0xFC, 0xF1, 0xFD, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xEA, 0xFA, 0xF1, 0xFA, 0xFD, 0xFF, 0xFD, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFD, 0xFE, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xFE, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xBA, 0xFB, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xFB, 0xF4, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFB, 0xFB, 0xF3, 0xFD, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFE, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFE, 0xF9, 0xFD,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xFD, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFC, 0xFE, 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFC, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF8, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xF5, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFD, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x9C, 0xA3, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x6F, 0x96, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x78, 0x5A, 0x4F, 0x85, 0x57, 0x55, 0x50, 0x6F,
+ 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x93, 0x88, 0x12, 0x00, 0x6A, 0x91, 0x01, 0x00, 0xB3, 0x79, 0x01, 0x00,
+ 0xDF, 0x01, 0x22, 0x00, 0xD0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x8F,
+ 0x0E, 0x12, 0x0E, 0x6B, 0x87, 0x40, 0x39, 0x44, 0x3C, 0x38, 0x80, 0x41,
+ 0x9F, 0x86, 0x80, 0x22, 0xEA, 0xBC, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x84, 0x02, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, 0x80, 0x02, 0x04, 0x06,
+ 0x81, 0x82, 0x83, 0x84, 0x80, 0x02, 0x81, 0x04, 0x82, 0x83, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08,
+ 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x04, 0x06, 0x80, 0x81,
+ 0x82, 0x83, 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x83, 0x02, 0x82, 0x04, 0x80, 0x81, 0x00, 0x00, 0x80, 0x02, 0x81, 0x04,
+ 0x82, 0x06, 0x08, 0x0C, 0x83, 0x0A, 0x85, 0x86, 0x84, 0x0E, 0x87, 0x10,
+ 0x88, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x8A, 0x02, 0x8B, 0x04, 0x8C, 0x8D, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x87, 0x02, 0x85, 0x04, 0x86, 0x06, 0x88, 0x89,
+};
+
+static const u8 vp8_mv_update_prob[2][19] = {
+ { 237, 246, 253, 253, 254, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 },
+ { 231, 243, 245, 253, 254, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 }
+};
+
+static uint8_t read_bits(struct cedrus_dev *dev, unsigned int bits_count,
+ unsigned int probability)
+{
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_VP8_GET_BITS |
+ VE_H264_TRIGGER_TYPE_BIN_LENS(bits_count) |
+ VE_H264_TRIGGER_TYPE_PROBABILITY(probability));
+
+ while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VLD_BUSY)
+ ;
+
+ return cedrus_read(dev, VE_H264_BASIC_BITS);
+}
+
+static void get_delta_q(struct cedrus_dev *dev)
+{
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 4, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+}
+
+static void process_segmentation_info(struct cedrus_dev *dev)
+{
+ int update = read_bits(dev, 1, VP8_PROB_HALF);
+ int i;
+
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 1, VP8_PROB_HALF);
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 7, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+ }
+
+ if (update)
+ for (i = 0; i < 3; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ read_bits(dev, 8, VP8_PROB_HALF);
+}
+
+static void process_ref_lf_delta_info(struct cedrus_dev *dev)
+{
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ int i;
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+
+ for (i = 0; i < 4; i++)
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+ }
+}
+
+static void process_ref_frame_info(struct cedrus_dev *dev)
+{
+ u8 refresh_golden_frame = read_bits(dev, 1, VP8_PROB_HALF);
+ u8 refresh_alt_ref_frame = read_bits(dev, 1, VP8_PROB_HALF);
+
+ if (!refresh_golden_frame)
+ read_bits(dev, 2, VP8_PROB_HALF);
+
+ if (!refresh_alt_ref_frame)
+ read_bits(dev, 2, VP8_PROB_HALF);
+
+ read_bits(dev, 1, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+}
+
+static void cedrus_read_header(struct cedrus_dev *dev,
+ const struct v4l2_ctrl_vp8_frame_header *slice)
+{
+ int i, j;
+
+ if (VP8_FRAME_IS_KEY_FRAME(slice)) {
+ read_bits(dev, 1, VP8_PROB_HALF);
+ read_bits(dev, 1, VP8_PROB_HALF);
+ }
+
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ process_segmentation_info(dev);
+
+ read_bits(dev, 1, VP8_PROB_HALF);
+ read_bits(dev, 6, VP8_PROB_HALF);
+ read_bits(dev, 3, VP8_PROB_HALF);
+
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ process_ref_lf_delta_info(dev);
+
+ read_bits(dev, 2, VP8_PROB_HALF);
+ read_bits(dev, 7, VP8_PROB_HALF);
+
+ get_delta_q(dev);
+ get_delta_q(dev);
+ get_delta_q(dev);
+ get_delta_q(dev);
+ get_delta_q(dev);
+
+ if (!VP8_FRAME_IS_KEY_FRAME(slice))
+ process_ref_frame_info(dev);
+
+ read_bits(dev, 1, VP8_PROB_HALF);
+
+ if (!VP8_FRAME_IS_KEY_FRAME(slice))
+ read_bits(dev, 1, VP8_PROB_HALF);
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE, VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF);
+ while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VP8_UPPROB_BUSY)
+ ;
+
+ cedrus_write(dev, VE_H264_STATUS, VE_H264_CTRL_INT_MASK);
+
+ if (read_bits(dev, 1, VP8_PROB_HALF))
+ read_bits(dev, 8, VP8_PROB_HALF);
+
+ if (!VP8_FRAME_IS_KEY_FRAME(slice)) {
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ }
+
+ if (read_bits(dev, 1, VP8_PROB_HALF)) {
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ read_bits(dev, 8, VP8_PROB_HALF);
+ }
+
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 19; j++)
+ if (read_bits(dev, 1, vp8_mv_update_prob[i][j]))
+ read_bits(dev, 7, VP8_PROB_HALF);
+ }
+}
+
+static void cedrus_vp8_update_probs(const struct v4l2_ctrl_vp8_frame_header *slice,
+ u8 *prob_table)
+{
+ int i, j, k;
+
+ memcpy(&prob_table[0x1008], slice->entropy_header.y_mode_probs, 4);
+ memcpy(&prob_table[0x1010], slice->entropy_header.uv_mode_probs, 3);
+
+ memcpy(&prob_table[0x1018], slice->segment_header.segment_probs, 3);
+
+ prob_table[0x101c] = slice->prob_skip_false;
+ prob_table[0x101d] = slice->prob_intra;
+ prob_table[0x101e] = slice->prob_last;
+ prob_table[0x101f] = slice->prob_gf;
+
+ memcpy(&prob_table[0x1020], slice->entropy_header.mv_probs[0], 19);
+ memcpy(&prob_table[0x1040], slice->entropy_header.mv_probs[1], 19);
+
+ for (i = 0; i < 4; ++i)
+ for (j = 0; j < 8; ++j)
+ for (k = 0; k < 3; ++k)
+ memcpy(&prob_table[i * 512 + j * 64 + k * 16],
+ slice->entropy_header.coeff_probs[i][j][k], 11);
+}
+
+static enum cedrus_irq_status
+cedrus_vp8_irq_status(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_H264_STATUS);
+
+ if (reg & (VE_H264_STATUS_DECODE_ERR_INT |
+ VE_H264_STATUS_VLD_DATA_REQ_INT))
+ return CEDRUS_IRQ_ERROR;
+
+ if (reg & VE_H264_CTRL_SLICE_DECODE_INT)
+ return CEDRUS_IRQ_OK;
+
+ return CEDRUS_IRQ_NONE;
+}
+
+static void cedrus_vp8_irq_clear(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_H264_STATUS,
+ VE_H264_STATUS_INT_MASK);
+}
+
+static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+ u32 reg = cedrus_read(dev, VE_H264_CTRL);
+
+ cedrus_write(dev, VE_H264_CTRL,
+ reg & ~VE_H264_CTRL_INT_MASK);
+}
+
+static void cedrus_vp8_setup(struct cedrus_ctx *ctx,
+ struct cedrus_run *run)
+{
+ const struct v4l2_ctrl_vp8_frame_header *slice = run->vp8.slice_params;
+ struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
+ struct vb2_buffer *src_buf = &run->src->vb2_buf;
+ struct cedrus_dev *dev = ctx->dev;
+ dma_addr_t luma_addr, chroma_addr;
+ dma_addr_t src_buf_addr;
+ int header_size;
+ int qindex;
+ u32 reg;
+
+ cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8);
+
+ cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8);
+
+ cedrus_vp8_update_probs(slice, ctx->codec.vp8.entropy_probs_buf);
+
+ reg = slice->first_part_size * 8;
+ cedrus_write(dev, VE_VP8_FIRST_DATA_PART_LEN, reg);
+
+ header_size = VP8_FRAME_IS_KEY_FRAME(slice) ? 10 : 3;
+
+ reg = slice->first_part_size + header_size;
+ cedrus_write(dev, VE_VP8_PART_SIZE_OFFSET, reg);
+
+ reg = vb2_plane_size(src_buf, 0) * 8;
+ cedrus_write(dev, VE_H264_VLD_LEN, reg);
+
+ /*
+ * FIXME: There is a problem if frame header is skipped (adding
+ * first_part_header_bits to offset). It seems that functions
+ * for parsing bitstreams change internal state of VPU in some
+ * way that can't be otherwise set. Maybe this can be bypassed
+ * by somehow fixing probability table buffer?
+ */
+ reg = header_size * 8;
+ cedrus_write(dev, VE_H264_VLD_OFFSET, reg);
+
+ src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ cedrus_write(dev, VE_H264_VLD_END,
+ src_buf_addr + vb2_get_plane_payload(src_buf, 0));
+ cedrus_write(dev, VE_H264_VLD_ADDR,
+ VE_H264_VLD_ADDR_VAL(src_buf_addr) |
+ VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID |
+ VE_H264_VLD_ADDR_LAST);
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_INIT_SWDEC);
+
+ cedrus_write(dev, VE_VP8_ENTROPY_PROBS_ADDR,
+ ctx->codec.vp8.entropy_probs_buf_dma);
+
+ reg = 0;
+ switch (slice->version) {
+ case 1:
+ reg |= VE_VP8_PPS_FILTER_TYPE_SIMPLE;
+ reg |= VE_VP8_PPS_BILINEAR_MC_FILTER;
+ break;
+ case 2:
+ reg |= VE_VP8_PPS_LPF_DISABLE;
+ reg |= VE_VP8_PPS_BILINEAR_MC_FILTER;
+ break;
+ case 3:
+ reg |= VE_VP8_PPS_LPF_DISABLE;
+ reg |= VE_VP8_PPS_FULL_PIXEL;
+ break;
+ }
+ if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP)
+ reg |= VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP;
+ if (!(slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE))
+ reg |= VE_VP8_PPS_MB_SEGMENT_ABS_DELTA;
+ if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)
+ reg |= VE_VP8_PPS_SEGMENTATION_ENABLE;
+ if (ctx->codec.vp8.last_filter_type)
+ reg |= VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE;
+ reg |= VE_VP8_PPS_SHARPNESS_LEVEL(slice->lf_header.sharpness_level);
+ if (slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE)
+ reg |= VE_VP8_PPS_LOOP_FILTER_SIMPLE;
+ reg |= VE_VP8_PPS_LOOP_FILTER_LEVEL(slice->lf_header.level);
+ if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE)
+ reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE;
+ if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_DELTA_UPDATE)
+ reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE;
+ reg |= VE_VP8_PPS_TOKEN_PARTITION(ilog2(slice->num_dct_parts));
+ if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)
+ reg |= VE_VP8_PPS_MB_NO_COEFF_SKIP;
+ reg |= VE_VP8_PPS_RELOAD_ENTROPY_PROBS;
+ if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN)
+ reg |= VE_VP8_PPS_GOLDEN_SIGN_BIAS;
+ if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT)
+ reg |= VE_VP8_PPS_ALTREF_SIGN_BIAS;
+ if (ctx->codec.vp8.last_frame_p_type)
+ reg |= VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME;
+ reg |= VE_VP8_PPS_LAST_SHARPNESS_LEVEL(ctx->codec.vp8.last_sharpness_level);
+ if (!(slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME))
+ reg |= VE_VP8_PPS_PIC_TYPE_P_FRAME;
+ cedrus_write(dev, VE_VP8_PPS, reg);
+
+ cedrus_read_header(dev, slice);
+
+ /* reset registers changed by HW */
+ cedrus_write(dev, VE_H264_CUR_MB_NUM, 0);
+ cedrus_write(dev, VE_H264_MB_ADDR, 0);
+ cedrus_write(dev, VE_H264_ERROR_CASE, 0);
+
+ reg = 0;
+ reg |= VE_VP8_QP_INDEX_DELTA_UVAC(slice->quant_header.uv_ac_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_UVDC(slice->quant_header.uv_dc_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_Y2AC(slice->quant_header.y2_ac_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_Y2DC(slice->quant_header.y2_dc_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_Y1DC(slice->quant_header.y_dc_delta);
+ reg |= VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(slice->quant_header.y_ac_qi);
+ cedrus_write(dev, VE_VP8_QP_INDEX_DELTA, reg);
+
+ reg = 0;
+ reg |= VE_VP8_FSIZE_WIDTH(slice->width);
+ reg |= VE_VP8_FSIZE_HEIGHT(slice->height);
+ cedrus_write(dev, VE_VP8_FSIZE, reg);
+
+ reg = 0;
+ reg |= VE_VP8_PICSIZE_WIDTH(slice->width);
+ reg |= VE_VP8_PICSIZE_HEIGHT(slice->height);
+ cedrus_write(dev, VE_VP8_PICSIZE, reg);
+
+ reg = 0;
+ reg |= VE_VP8_SEGMENT3(slice->segment_header.quant_update[3]);
+ reg |= VE_VP8_SEGMENT2(slice->segment_header.quant_update[2]);
+ reg |= VE_VP8_SEGMENT1(slice->segment_header.quant_update[1]);
+ reg |= VE_VP8_SEGMENT0(slice->segment_header.quant_update[0]);
+ cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV0, reg);
+
+ reg = 0;
+ reg |= VE_VP8_SEGMENT3(slice->segment_header.lf_update[3]);
+ reg |= VE_VP8_SEGMENT2(slice->segment_header.lf_update[2]);
+ reg |= VE_VP8_SEGMENT1(slice->segment_header.lf_update[1]);
+ reg |= VE_VP8_SEGMENT0(slice->segment_header.lf_update[0]);
+ cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV1, reg);
+
+ reg = 0;
+ reg |= VE_VP8_LF_DELTA3(slice->lf_header.ref_frm_delta[3]);
+ reg |= VE_VP8_LF_DELTA2(slice->lf_header.ref_frm_delta[2]);
+ reg |= VE_VP8_LF_DELTA1(slice->lf_header.ref_frm_delta[1]);
+ reg |= VE_VP8_LF_DELTA0(slice->lf_header.ref_frm_delta[0]);
+ cedrus_write(dev, VE_VP8_REF_LF_DELTA, reg);
+
+ reg = 0;
+ reg |= VE_VP8_LF_DELTA3(slice->lf_header.mb_mode_delta[3]);
+ reg |= VE_VP8_LF_DELTA2(slice->lf_header.mb_mode_delta[2]);
+ reg |= VE_VP8_LF_DELTA1(slice->lf_header.mb_mode_delta[1]);
+ reg |= VE_VP8_LF_DELTA0(slice->lf_header.mb_mode_delta[0]);
+ cedrus_write(dev, VE_VP8_MODE_LF_DELTA, reg);
+
+ luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1);
+ cedrus_write(dev, VE_VP8_REC_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_REC_CHROMA, chroma_addr);
+
+ qindex = vb2_find_timestamp(cap_q, slice->last_frame_ts, 0);
+ if (qindex >= 0) {
+ luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
+ cedrus_write(dev, VE_VP8_FWD_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_FWD_CHROMA, chroma_addr);
+ } else {
+ cedrus_write(dev, VE_VP8_FWD_LUMA, 0);
+ cedrus_write(dev, VE_VP8_FWD_CHROMA, 0);
+ }
+
+ qindex = vb2_find_timestamp(cap_q, slice->golden_frame_ts, 0);
+ if (qindex >= 0) {
+ luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
+ cedrus_write(dev, VE_VP8_BWD_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_BWD_CHROMA, chroma_addr);
+ } else {
+ cedrus_write(dev, VE_VP8_BWD_LUMA, 0);
+ cedrus_write(dev, VE_VP8_BWD_CHROMA, 0);
+ }
+
+ qindex = vb2_find_timestamp(cap_q, slice->alt_frame_ts, 0);
+ if (qindex >= 0) {
+ luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0);
+ chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1);
+ cedrus_write(dev, VE_VP8_ALT_LUMA, luma_addr);
+ cedrus_write(dev, VE_VP8_ALT_CHROMA, chroma_addr);
+ } else {
+ cedrus_write(dev, VE_VP8_ALT_LUMA, 0);
+ cedrus_write(dev, VE_VP8_ALT_CHROMA, 0);
+ }
+
+ cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8 |
+ VE_H264_CTRL_DECODE_ERR_INT |
+ VE_H264_CTRL_SLICE_DECODE_INT);
+
+ if (slice->lf_header.level) {
+ ctx->codec.vp8.last_filter_type =
+ !!(slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE);
+ ctx->codec.vp8.last_frame_p_type =
+ !VP8_FRAME_IS_KEY_FRAME(slice);
+ ctx->codec.vp8.last_sharpness_level =
+ slice->lf_header.sharpness_level;
+ }
+}
+
+static int cedrus_vp8_start(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ ctx->codec.vp8.entropy_probs_buf =
+ dma_alloc_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE,
+ &ctx->codec.vp8.entropy_probs_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->codec.vp8.entropy_probs_buf)
+ return -ENOMEM;
+
+ memcpy(&ctx->codec.vp8.entropy_probs_buf[2048],
+ prob_table_init, sizeof(prob_table_init));
+
+ return 0;
+}
+
+static void cedrus_vp8_stop(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_engine_disable(dev);
+
+ dma_free_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE,
+ ctx->codec.vp8.entropy_probs_buf,
+ ctx->codec.vp8.entropy_probs_buf_dma);
+}
+
+static void cedrus_vp8_trigger(struct cedrus_ctx *ctx)
+{
+ struct cedrus_dev *dev = ctx->dev;
+
+ cedrus_write(dev, VE_H264_TRIGGER_TYPE,
+ VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE);
+}
+
+struct cedrus_dec_ops cedrus_dec_ops_vp8 = {
+ .irq_clear = cedrus_vp8_irq_clear,
+ .irq_disable = cedrus_vp8_irq_disable,
+ .irq_status = cedrus_vp8_irq_status,
+ .setup = cedrus_vp8_setup,
+ .start = cedrus_vp8_start,
+ .stop = cedrus_vp8_stop,
+ .trigger = cedrus_vp8_trigger,
+};

View File

@ -0,0 +1,57 @@
From f826ffb93b1ba0cfb9a5cfa3403813674331d4e0 Mon Sep 17 00:00:00 2001
From: Jonas Karlman <jonas@kwiboo.se>
Date: Tue, 26 Feb 2019 20:45:14 +0000
Subject: [PATCH 34/44] WIP: dw-hdmi-cec: sleep 100ms on error
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2015-2017 Russell King.
*/
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -129,8 +130,15 @@ static irqreturn_t dw_hdmi_cec_hardirq(i
dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0);
- if (stat & CEC_STAT_ERROR_INIT) {
- cec->tx_status = CEC_TX_STATUS_ERROR;
+ /* Status with both done and error_initiator bits have been seen
+ * on Rockchip RK3328 devices, transmit attempt seems to have failed
+ * when this happens, report as low drive and block cec-framework
+ * 100ms before core retransmits the failed message, this seems to
+ * mitigate the issue with failed transmit attempts.
+ */
+ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) {
+ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat);
+ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
} else if (stat & CEC_STAT_DONE) {
@@ -141,6 +149,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(i
cec->tx_status = CEC_TX_STATUS_NACK;
cec->tx_done = true;
ret = IRQ_WAKE_THREAD;
+ } else if (stat & CEC_STAT_ERROR_INIT) {
+ cec->tx_status = CEC_TX_STATUS_ERROR;
+ cec->tx_done = true;
+ ret = IRQ_WAKE_THREAD;
}
if (stat & CEC_STAT_EOM) {
@@ -173,6 +185,8 @@ static irqreturn_t dw_hdmi_cec_thread(in
if (cec->tx_done) {
cec->tx_done = false;
+ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE)
+ msleep(100);
cec_transmit_attempt_done(adap, cec->tx_status);
}
if (cec->rx_done) {

View File

@ -1,7 +1,7 @@
From 8132877d34935f3d0a2c661f00f67f782b6bc8f8 Mon Sep 17 00:00:00 2001
From f1c04148f8cc62bf99cb06e348f04452d307ebc8 Mon Sep 17 00:00:00 2001
From: Roman Stratiienko <roman.stratiienko@globallogic.com>
Date: Sat, 28 Dec 2019 22:28:17 +0200
Subject: [PATCH 1/3] drm/sun4i: Reimplement plane z position setting logic
Subject: [PATCH 35/44] drm/sun4i: Reimplement plane z position setting logic
To set blending channel order register software needs to know state and
position of each channel, which impossible at plane commit stage.
@ -18,14 +18,13 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 39 +++--------------------
4 files changed, 57 insertions(+), 72 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index cc4fb916318f..1ad704b737cf 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -250,8 +250,45 @@ int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format)
@@ -250,8 +250,45 @@ int sun8i_mixer_drm_format_to_hw(u32 for
static void sun8i_mixer_commit(struct sunxi_engine *engine)
{
- DRM_DEBUG_DRIVER("Committing changes\n");
+ struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+ int channel_by_zpos[SUN8I_MIXER_MAX_CHANNELS];
+ u32 base = sun8i_blender_base(mixer);
@ -46,7 +45,7 @@ index cc4fb916318f..1ad704b737cf 100644
+ if (zpos >= 0 && zpos < channel_count)
+ channel_by_zpos[zpos] = i;
+ }
+
+ j = 0;
+ for (i = 0; i < channel_count; i++) {
+ int ch = channel_by_zpos[i];
@ -64,12 +63,11 @@ index cc4fb916318f..1ad704b737cf 100644
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_ROUTE(base), route);
+
DRM_DEBUG_DRIVER("Committing changes\n");
-
+ DRM_DEBUG_DRIVER("Committing changes\n");
regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
}
@@ -489,10 +526,12 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
@@ -489,10 +526,12 @@ static int sun8i_mixer_bind(struct devic
SUN8I_MIXER_BLEND_COLOR_BLACK);
plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
@ -83,8 +81,6 @@ index cc4fb916318f..1ad704b737cf 100644
regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 7576b523fdbb..7b378d6e4dd9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -12,6 +12,8 @@
@ -96,7 +92,7 @@ index 7576b523fdbb..7b378d6e4dd9 100644
#define SUN8I_MIXER_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
#define SUN8I_MIXER_COORD(x, y) ((y) << 16 | (x))
@@ -179,6 +181,9 @@ struct sun8i_mixer {
@@ -177,6 +179,9 @@ struct sun8i_mixer {
struct clk *bus_clk;
struct clk *mod_clk;
@ -106,8 +102,6 @@ index 7576b523fdbb..7b378d6e4dd9 100644
};
static inline struct sun8i_mixer *
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 54f937a7d5e7..651d3bf096c6 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -24,12 +24,10 @@
@ -125,7 +119,7 @@ index 54f937a7d5e7..651d3bf096c6 100644
ch_base = sun8i_channel_base(mixer, channel);
DRM_DEBUG_DRIVER("%sabling channel %d overlay %d\n",
@@ -44,32 +42,7 @@ static void sun8i_ui_layer_enable(struct sun8i_mixer *mixer, int channel,
@@ -44,32 +42,7 @@ static void sun8i_ui_layer_enable(struct
SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
@ -159,7 +153,7 @@ index 54f937a7d5e7..651d3bf096c6 100644
}
static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
@@ -267,11 +240,9 @@ static void sun8i_ui_layer_atomic_disable(struct drm_plane *plane,
@@ -267,11 +240,9 @@ static void sun8i_ui_layer_atomic_disabl
struct drm_plane_state *old_state)
{
struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
@ -172,7 +166,7 @@ index 54f937a7d5e7..651d3bf096c6 100644
}
static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
@@ -279,12 +250,11 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
@@ -279,12 +250,11 @@ static void sun8i_ui_layer_atomic_update
{
struct sun8i_ui_layer *layer = plane_to_sun8i_ui_layer(plane);
unsigned int zpos = plane->state->normalized_zpos;
@ -186,7 +180,7 @@ index 54f937a7d5e7..651d3bf096c6 100644
return;
}
@@ -295,7 +265,7 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
@@ -295,7 +265,7 @@ static void sun8i_ui_layer_atomic_update
sun8i_ui_layer_update_buffer(mixer, layer->channel,
layer->overlay, plane);
sun8i_ui_layer_enable(mixer, layer->channel, layer->overlay,
@ -194,9 +188,7 @@ index 54f937a7d5e7..651d3bf096c6 100644
+ true, zpos);
}
static struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 22c8c5375d0d..bd28e76363d9 100644
static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -18,8 +18,7 @@
@ -209,7 +201,7 @@ index 22c8c5375d0d..bd28e76363d9 100644
{
u32 val, bld_base, ch_base;
@@ -38,32 +37,7 @@ static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
@@ -38,32 +37,7 @@ static void sun8i_vi_layer_enable(struct
SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
@ -243,7 +235,7 @@ index 22c8c5375d0d..bd28e76363d9 100644
}
static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
@@ -370,11 +344,9 @@ static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
@@ -370,11 +344,9 @@ static void sun8i_vi_layer_atomic_disabl
struct drm_plane_state *old_state)
{
struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
@ -256,7 +248,7 @@ index 22c8c5375d0d..bd28e76363d9 100644
}
static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
@@ -382,12 +354,11 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
@@ -382,12 +354,11 @@ static void sun8i_vi_layer_atomic_update
{
struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
unsigned int zpos = plane->state->normalized_zpos;
@ -270,7 +262,7 @@ index 22c8c5375d0d..bd28e76363d9 100644
return;
}
@@ -398,7 +369,7 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
@@ -398,7 +369,7 @@ static void sun8i_vi_layer_atomic_update
sun8i_vi_layer_update_buffer(mixer, layer->channel,
layer->overlay, plane);
sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
@ -278,112 +270,4 @@ index 22c8c5375d0d..bd28e76363d9 100644
+ true, zpos);
}
static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
--
2.27.0
From 9d11b18afdb63d60714a78c5966f674aa66ee6b9 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 19 Jul 2020 11:28:49 +0200
Subject: [PATCH 2/3] drm/sun4i: Don't use update regmap variant for blend pipe
register
Readout might return invalid value, so always write it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 1ad704b737cf..8825518e06c8 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -282,8 +282,14 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine)
}
}
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, pipe_ctl);
+ /*
+ * Set fill color of bottom plane to black. Generally not needed
+ * except when VI plane is at bottom (zpos = 0) and enabled.
+ */
+ pipe_ctl |= SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0);
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_PIPE_CTL(base), pipe_ctl);
regmap_write(mixer->engine.regs,
SUN8I_MIXER_BLEND_ROUTE(base), route);
@@ -516,12 +522,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
SUN8I_MIXER_BLEND_COLOR_BLACK);
- /*
- * Set fill color of bottom plane to black. Generally not needed
- * except when VI plane is at bottom (zpos = 0) and enabled.
- */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
SUN8I_MIXER_BLEND_COLOR_BLACK);
@@ -533,9 +533,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
mixer->channel_zpos[i] = -1;
}
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
-
return 0;
err_disable_bus_clk:
--
2.27.0
From bb41e6a8620fc7c3fd91be8155ef5972ea04c0c8 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 19 Jul 2020 11:37:41 +0200
Subject: [PATCH 3/3] drm/sun4i: mixer: Add caching support
Most registers are not safe to read out so enable cache in regmap.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 8825518e06c8..006b746b0e95 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -346,11 +346,23 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
.layers_init = sun8i_layers_init,
};
+static bool sun8i_mixer_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SUN8I_MIXER_GLOBAL_STATUS:
+ case SUN8I_MIXER_GLOBAL_DBUFF:
+ return true;
+ }
+ return false;
+}
+
static const struct regmap_config sun8i_mixer_regmap_config = {
+ .cache_type = REGCACHE_FLAT,
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0xffffc, /* guessed */
+ .volatile_reg = sun8i_mixer_volatile_reg,
};
static int sun8i_mixer_of_get_id(struct device_node *node)
--
2.27.0
static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {

View File

@ -0,0 +1,55 @@
From 144ad308ded7c5617d9574e174b68cbcb622cf4c Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 19 Jul 2020 11:28:49 +0200
Subject: [PATCH 36/44] drm/sun4i: Don't use update regmap variant for blend
pipe register
Readout might return invalid value, so always write it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -282,8 +282,14 @@ static void sun8i_mixer_commit(struct su
}
}
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, pipe_ctl);
+ /*
+ * Set fill color of bottom plane to black. Generally not needed
+ * except when VI plane is at bottom (zpos = 0) and enabled.
+ */
+ pipe_ctl |= SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0);
+
+ regmap_write(mixer->engine.regs,
+ SUN8I_MIXER_BLEND_PIPE_CTL(base), pipe_ctl);
regmap_write(mixer->engine.regs,
SUN8I_MIXER_BLEND_ROUTE(base), route);
@@ -516,12 +522,6 @@ static int sun8i_mixer_bind(struct devic
regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
SUN8I_MIXER_BLEND_COLOR_BLACK);
- /*
- * Set fill color of bottom plane to black. Generally not needed
- * except when VI plane is at bottom (zpos = 0) and enabled.
- */
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
SUN8I_MIXER_BLEND_COLOR_BLACK);
@@ -533,9 +533,6 @@ static int sun8i_mixer_bind(struct devic
mixer->channel_zpos[i] = -1;
}
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
- SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
-
return 0;
err_disable_bus_clk:

View File

@ -0,0 +1,38 @@
From 2e5d4ca1c07ddf06f8c3b18fd73baea7ce711169 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sun, 19 Jul 2020 11:37:41 +0200
Subject: [PATCH 37/44] drm/sun4i: mixer: Add caching support
Most registers are not safe to read out so enable cache in regmap.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -346,11 +346,23 @@ static const struct sunxi_engine_ops sun
.layers_init = sun8i_layers_init,
};
+static bool sun8i_mixer_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SUN8I_MIXER_GLOBAL_STATUS:
+ case SUN8I_MIXER_GLOBAL_DBUFF:
+ return true;
+ }
+ return false;
+}
+
static const struct regmap_config sun8i_mixer_regmap_config = {
+ .cache_type = REGCACHE_FLAT,
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0xffffc, /* guessed */
+ .volatile_reg = sun8i_mixer_volatile_reg,
};
static int sun8i_mixer_of_get_id(struct device_node *node)

View File

@ -1,7 +1,7 @@
From fe3aef9d51c82c286ff33d867b59d0fae9a6dddd Mon Sep 17 00:00:00 2001
From 59adceb6f34521c0f1a229f20ee9961269daa539 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 16 Aug 2019 16:38:21 +0200
Subject: [PATCH 1/2] mfd: Add support for AC200
Subject: [PATCH 38/44] mfd: Add support for AC200
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
@ -13,8 +13,6 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
create mode 100644 drivers/mfd/ac200.c
create mode 100644 include/linux/mfd/ac200.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 4a07afe50b35..576db86dfa79 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -178,6 +178,15 @@ config MFD_AC100
@ -33,11 +31,9 @@ index 4a07afe50b35..576db86dfa79 100644
config MFD_AXP20X
tristate
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 7b6a6aa4fe42..7981edcbff4a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -143,6 +143,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
@@ -143,6 +143,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-s
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
obj-$(CONFIG_MFD_AC100) += ac100.o
@ -45,9 +41,6 @@ index 7b6a6aa4fe42..7981edcbff4a 100644
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
diff --git a/drivers/mfd/ac200.c b/drivers/mfd/ac200.c
new file mode 100644
index 000000000000..3c95be216cf0
--- /dev/null
+++ b/drivers/mfd/ac200.c
@@ -0,0 +1,150 @@
@ -201,9 +194,6 @@ index 000000000000..3c95be216cf0
+MODULE_DESCRIPTION("MFD core driver for AC200");
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/ac200.h b/include/linux/mfd/ac200.h
new file mode 100644
index 000000000000..48a21d5c354a
--- /dev/null
+++ b/include/linux/mfd/ac200.h
@@ -0,0 +1,209 @@
@ -416,293 +406,3 @@ index 000000000000..48a21d5c354a
+};
+
+#endif /* __LINUX_MFD_AC200_H */
--
2.22.1
From d570d779f96ce5abc1f215eb11bbe0401b539f4b Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 16 Aug 2019 16:38:57 +0200
Subject: [PATCH 2/2] net: phy: Add support for AC200 EPHY
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/net/phy/Kconfig | 7 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/ac200.c | 234 +++++++++++++++++++++++++++++++++++++++
3 files changed, 242 insertions(+)
create mode 100644 drivers/net/phy/ac200.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 48ca213c0ada..37012117fc7a 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -257,6 +257,13 @@ config SFP
depends on HWMON || HWMON=n
select MDIO_I2C
+config AC200_PHY
+ tristate "AC200 EPHY"
+ depends on NVMEM
+ depends on OF
+ help
+ Fast ethernet PHY as found in X-Powers AC200 multi-function device.
+
config AMD_PHY
tristate "AMD PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index ba07c27e4208..8fab8dfbe94e 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_SFP) += sfp.o
sfp-obj-$(CONFIG_SFP) += sfp-bus.o
obj-y += $(sfp-obj-y) $(sfp-obj-m)
+obj-$(CONFIG_AC200_PHY) += ac200.o
obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_AMD_PHY) += amd.o
aquantia-objs += aquantia_main.o
diff --git a/drivers/net/phy/ac200.c b/drivers/net/phy/ac200.c
new file mode 100644
index 000000000000..e36af123db43
--- /dev/null
+++ b/drivers/net/phy/ac200.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Driver for AC200 Ethernet PHY
+ *
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/ac200.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+#define AC200_EPHY_ID 0x00441400
+#define AC200_EPHY_ID_MASK 0x0ffffff0
+
+/* macros for system ephy control 0 register */
+#define AC200_EPHY_RESET_INVALID BIT(0)
+#define AC200_EPHY_SYSCLK_GATING BIT(1)
+
+/* macros for system ephy control 1 register */
+#define AC200_EPHY_E_EPHY_MII_IO_EN BIT(0)
+#define AC200_EPHY_E_LNK_LED_IO_EN BIT(1)
+#define AC200_EPHY_E_SPD_LED_IO_EN BIT(2)
+#define AC200_EPHY_E_DPX_LED_IO_EN BIT(3)
+
+/* macros for ephy control register */
+#define AC200_EPHY_SHUTDOWN BIT(0)
+#define AC200_EPHY_LED_POL BIT(1)
+#define AC200_EPHY_CLK_SEL BIT(2)
+#define AC200_EPHY_ADDR(x) (((x) & 0x1F) << 4)
+#define AC200_EPHY_XMII_SEL BIT(11)
+#define AC200_EPHY_CALIB(x) (((x) & 0xF) << 12)
+
+struct ac200_ephy_dev {
+ struct phy_driver *ephy;
+ struct regmap *regmap;
+};
+
+static char *ac200_phy_name = "AC200 EPHY";
+
+static void disable_intelligent_ieee(struct phy_device *phydev)
+{
+ unsigned int value;
+
+ phy_write(phydev, 0x1f, 0x0100); /* switch to page 1 */
+ value = phy_read(phydev, 0x17);
+ value &= ~BIT(3); /* disable IEEE */
+ phy_write(phydev, 0x17, value);
+ phy_write(phydev, 0x1f, 0x0000); /* switch to page 0 */
+}
+
+static void disable_802_3az_ieee(struct phy_device *phydev)
+{
+ unsigned int value;
+
+ phy_write(phydev, 0xd, 0x7);
+ phy_write(phydev, 0xe, 0x3c);
+ phy_write(phydev, 0xd, BIT(14) | 0x7);
+ value = phy_read(phydev, 0xe);
+ value &= ~BIT(1);
+ phy_write(phydev, 0xd, 0x7);
+ phy_write(phydev, 0xe, 0x3c);
+ phy_write(phydev, 0xd, BIT(14) | 0x7);
+ phy_write(phydev, 0xe, value);
+
+ phy_write(phydev, 0x1f, 0x0200); /* switch to page 2 */
+ phy_write(phydev, 0x18, 0x0000);
+}
+
+static int ac200_ephy_config_init(struct phy_device *phydev)
+{
+ const struct ac200_ephy_dev *priv = phydev->drv->driver_data;
+ unsigned int value;
+ int ret;
+
+ phy_write(phydev, 0x1f, 0x0100); /* Switch to Page 1 */
+ phy_write(phydev, 0x12, 0x4824); /* Disable APS */
+
+ phy_write(phydev, 0x1f, 0x0200); /* Switch to Page 2 */
+ phy_write(phydev, 0x18, 0x0000); /* PHYAFE TRX optimization */
+
+ phy_write(phydev, 0x1f, 0x0600); /* Switch to Page 6 */
+ phy_write(phydev, 0x14, 0x708f); /* PHYAFE TX optimization */
+ phy_write(phydev, 0x13, 0xF000); /* PHYAFE RX optimization */
+ phy_write(phydev, 0x15, 0x1530);
+
+ phy_write(phydev, 0x1f, 0x0800); /* Switch to Page 6 */
+ phy_write(phydev, 0x18, 0x00bc); /* PHYAFE TRX optimization */
+
+ disable_intelligent_ieee(phydev); /* Disable Intelligent IEEE */
+ disable_802_3az_ieee(phydev); /* Disable 802.3az IEEE */
+ phy_write(phydev, 0x1f, 0x0000); /* Switch to Page 0 */
+
+ value = (phydev->interface == PHY_INTERFACE_MODE_RMII) ?
+ AC200_EPHY_XMII_SEL : 0;
+ ret = regmap_update_bits(priv->regmap, AC200_EPHY_CTL,
+ AC200_EPHY_XMII_SEL, value);
+ if (ret)
+ return ret;
+
+ /* FIXME: This is probably H6 specific */
+ value = phy_read(phydev, 0x13);
+ value |= BIT(12);
+ phy_write(phydev, 0x13, value);
+
+ return 0;
+}
+
+static const struct mdio_device_id __maybe_unused ac200_ephy_phy_tbl[] = {
+ { AC200_EPHY_ID, AC200_EPHY_ID_MASK },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(mdio, ac200_ephy_phy_tbl);
+
+static int ac200_ephy_probe(struct platform_device *pdev)
+{
+ struct ac200_dev *ac200 = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct ac200_ephy_dev *priv;
+ struct nvmem_cell *calcell;
+ struct phy_driver *ephy;
+ u16 *caldata, calib;
+ size_t callen;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL);
+ if (!ephy)
+ return -ENOMEM;
+
+ calcell = devm_nvmem_cell_get(dev, "ephy_calib");
+ if (IS_ERR(calcell)) {
+ dev_err(dev, "Unable to find calibration data!\n");
+ return PTR_ERR(calcell);
+ }
+
+ caldata = nvmem_cell_read(calcell, &callen);
+ if (IS_ERR(caldata)) {
+ dev_err(dev, "Unable to read calibration data!\n");
+ return PTR_ERR(caldata);
+ }
+
+ if (callen != 2) {
+ dev_err(dev, "Calibration data has wrong length: 2 != %lu\n",
+ callen);
+ kfree(caldata);
+ return -EINVAL;
+ }
+
+ calib = *caldata + 3;
+ kfree(caldata);
+
+ ephy->phy_id = AC200_EPHY_ID;
+ ephy->phy_id_mask = AC200_EPHY_ID_MASK;
+ ephy->name = ac200_phy_name;
+ ephy->driver_data = priv;
+ ephy->soft_reset = genphy_soft_reset;
+ ephy->config_init = ac200_ephy_config_init;
+ ephy->suspend = genphy_suspend;
+ ephy->resume = genphy_resume;
+
+ priv->ephy = ephy;
+ priv->regmap = ac200->regmap;
+ platform_set_drvdata(pdev, priv);
+
+ ret = regmap_write(ac200->regmap, AC200_SYS_EPHY_CTL0,
+ AC200_EPHY_RESET_INVALID |
+ AC200_EPHY_SYSCLK_GATING);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ac200->regmap, AC200_SYS_EPHY_CTL1,
+ AC200_EPHY_E_EPHY_MII_IO_EN |
+ AC200_EPHY_E_LNK_LED_IO_EN |
+ AC200_EPHY_E_SPD_LED_IO_EN |
+ AC200_EPHY_E_DPX_LED_IO_EN);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ac200->regmap, AC200_EPHY_CTL,
+ AC200_EPHY_LED_POL |
+ AC200_EPHY_CLK_SEL |
+ AC200_EPHY_ADDR(1) |
+ AC200_EPHY_CALIB(calib));
+ if (ret)
+ return ret;
+
+ ret = phy_driver_register(priv->ephy, THIS_MODULE);
+ if (ret) {
+ dev_err(dev, "Unable to register phy\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ac200_ephy_remove(struct platform_device *pdev)
+{
+ struct ac200_ephy_dev *priv = platform_get_drvdata(pdev);
+
+ phy_driver_unregister(priv->ephy);
+
+ regmap_write(priv->regmap, AC200_EPHY_CTL, AC200_EPHY_SHUTDOWN);
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1, 0);
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0, 0);
+
+ return 0;
+}
+
+static const struct of_device_id ac200_ephy_match[] = {
+ { .compatible = "x-powers,ac200-ephy" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ac200_ephy_match);
+
+static struct platform_driver ac200_ephy_driver = {
+ .probe = ac200_ephy_probe,
+ .remove = ac200_ephy_remove,
+ .driver = {
+ .name = "ac200-ephy",
+ .of_match_table = ac200_ephy_match,
+ },
+};
+module_platform_driver(ac200_ephy_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("AC200 Ethernet PHY driver");
+MODULE_LICENSE("GPL");
--
2.22.1

View File

@ -0,0 +1,276 @@
From cbf68fb141747879e2e6c43584c1e1e3b4d77683 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 16 Aug 2019 16:38:57 +0200
Subject: [PATCH 39/44] net: phy: Add support for AC200 EPHY
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/net/phy/Kconfig | 7 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/ac200.c | 234 +++++++++++++++++++++++++++++++++++++++
3 files changed, 242 insertions(+)
create mode 100644 drivers/net/phy/ac200.c
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -63,6 +63,13 @@ config SFP
comment "MII PHY device drivers"
+config AC200_PHY
+ tristate "AC200 EPHY"
+ depends on NVMEM
+ depends on OF
+ help
+ Fast ethernet PHY as found in X-Powers AC200 multi-function device.
+
config AMD_PHY
tristate "AMD PHYs"
help
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_SFP) += sfp.o
sfp-obj-$(CONFIG_SFP) += sfp-bus.o
obj-y += $(sfp-obj-y) $(sfp-obj-m)
+obj-$(CONFIG_AC200_PHY) += ac200.o
obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_AMD_PHY) += amd.o
aquantia-objs += aquantia_main.o
--- /dev/null
+++ b/drivers/net/phy/ac200.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Driver for AC200 Ethernet PHY
+ *
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/ac200.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
+#define AC200_EPHY_ID 0x00441400
+#define AC200_EPHY_ID_MASK 0x0ffffff0
+
+/* macros for system ephy control 0 register */
+#define AC200_EPHY_RESET_INVALID BIT(0)
+#define AC200_EPHY_SYSCLK_GATING BIT(1)
+
+/* macros for system ephy control 1 register */
+#define AC200_EPHY_E_EPHY_MII_IO_EN BIT(0)
+#define AC200_EPHY_E_LNK_LED_IO_EN BIT(1)
+#define AC200_EPHY_E_SPD_LED_IO_EN BIT(2)
+#define AC200_EPHY_E_DPX_LED_IO_EN BIT(3)
+
+/* macros for ephy control register */
+#define AC200_EPHY_SHUTDOWN BIT(0)
+#define AC200_EPHY_LED_POL BIT(1)
+#define AC200_EPHY_CLK_SEL BIT(2)
+#define AC200_EPHY_ADDR(x) (((x) & 0x1F) << 4)
+#define AC200_EPHY_XMII_SEL BIT(11)
+#define AC200_EPHY_CALIB(x) (((x) & 0xF) << 12)
+
+struct ac200_ephy_dev {
+ struct phy_driver *ephy;
+ struct regmap *regmap;
+};
+
+static char *ac200_phy_name = "AC200 EPHY";
+
+static void disable_intelligent_ieee(struct phy_device *phydev)
+{
+ unsigned int value;
+
+ phy_write(phydev, 0x1f, 0x0100); /* switch to page 1 */
+ value = phy_read(phydev, 0x17);
+ value &= ~BIT(3); /* disable IEEE */
+ phy_write(phydev, 0x17, value);
+ phy_write(phydev, 0x1f, 0x0000); /* switch to page 0 */
+}
+
+static void disable_802_3az_ieee(struct phy_device *phydev)
+{
+ unsigned int value;
+
+ phy_write(phydev, 0xd, 0x7);
+ phy_write(phydev, 0xe, 0x3c);
+ phy_write(phydev, 0xd, BIT(14) | 0x7);
+ value = phy_read(phydev, 0xe);
+ value &= ~BIT(1);
+ phy_write(phydev, 0xd, 0x7);
+ phy_write(phydev, 0xe, 0x3c);
+ phy_write(phydev, 0xd, BIT(14) | 0x7);
+ phy_write(phydev, 0xe, value);
+
+ phy_write(phydev, 0x1f, 0x0200); /* switch to page 2 */
+ phy_write(phydev, 0x18, 0x0000);
+}
+
+static int ac200_ephy_config_init(struct phy_device *phydev)
+{
+ const struct ac200_ephy_dev *priv = phydev->drv->driver_data;
+ unsigned int value;
+ int ret;
+
+ phy_write(phydev, 0x1f, 0x0100); /* Switch to Page 1 */
+ phy_write(phydev, 0x12, 0x4824); /* Disable APS */
+
+ phy_write(phydev, 0x1f, 0x0200); /* Switch to Page 2 */
+ phy_write(phydev, 0x18, 0x0000); /* PHYAFE TRX optimization */
+
+ phy_write(phydev, 0x1f, 0x0600); /* Switch to Page 6 */
+ phy_write(phydev, 0x14, 0x708f); /* PHYAFE TX optimization */
+ phy_write(phydev, 0x13, 0xF000); /* PHYAFE RX optimization */
+ phy_write(phydev, 0x15, 0x1530);
+
+ phy_write(phydev, 0x1f, 0x0800); /* Switch to Page 6 */
+ phy_write(phydev, 0x18, 0x00bc); /* PHYAFE TRX optimization */
+
+ disable_intelligent_ieee(phydev); /* Disable Intelligent IEEE */
+ disable_802_3az_ieee(phydev); /* Disable 802.3az IEEE */
+ phy_write(phydev, 0x1f, 0x0000); /* Switch to Page 0 */
+
+ value = (phydev->interface == PHY_INTERFACE_MODE_RMII) ?
+ AC200_EPHY_XMII_SEL : 0;
+ ret = regmap_update_bits(priv->regmap, AC200_EPHY_CTL,
+ AC200_EPHY_XMII_SEL, value);
+ if (ret)
+ return ret;
+
+ /* FIXME: This is probably H6 specific */
+ value = phy_read(phydev, 0x13);
+ value |= BIT(12);
+ phy_write(phydev, 0x13, value);
+
+ return 0;
+}
+
+static const struct mdio_device_id __maybe_unused ac200_ephy_phy_tbl[] = {
+ { AC200_EPHY_ID, AC200_EPHY_ID_MASK },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(mdio, ac200_ephy_phy_tbl);
+
+static int ac200_ephy_probe(struct platform_device *pdev)
+{
+ struct ac200_dev *ac200 = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct ac200_ephy_dev *priv;
+ struct nvmem_cell *calcell;
+ struct phy_driver *ephy;
+ u16 *caldata, calib;
+ size_t callen;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL);
+ if (!ephy)
+ return -ENOMEM;
+
+ calcell = devm_nvmem_cell_get(dev, "ephy_calib");
+ if (IS_ERR(calcell)) {
+ dev_err(dev, "Unable to find calibration data!\n");
+ return PTR_ERR(calcell);
+ }
+
+ caldata = nvmem_cell_read(calcell, &callen);
+ if (IS_ERR(caldata)) {
+ dev_err(dev, "Unable to read calibration data!\n");
+ return PTR_ERR(caldata);
+ }
+
+ if (callen != 2) {
+ dev_err(dev, "Calibration data has wrong length: 2 != %lu\n",
+ callen);
+ kfree(caldata);
+ return -EINVAL;
+ }
+
+ calib = *caldata + 3;
+ kfree(caldata);
+
+ ephy->phy_id = AC200_EPHY_ID;
+ ephy->phy_id_mask = AC200_EPHY_ID_MASK;
+ ephy->name = ac200_phy_name;
+ ephy->driver_data = priv;
+ ephy->soft_reset = genphy_soft_reset;
+ ephy->config_init = ac200_ephy_config_init;
+ ephy->suspend = genphy_suspend;
+ ephy->resume = genphy_resume;
+
+ priv->ephy = ephy;
+ priv->regmap = ac200->regmap;
+ platform_set_drvdata(pdev, priv);
+
+ ret = regmap_write(ac200->regmap, AC200_SYS_EPHY_CTL0,
+ AC200_EPHY_RESET_INVALID |
+ AC200_EPHY_SYSCLK_GATING);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ac200->regmap, AC200_SYS_EPHY_CTL1,
+ AC200_EPHY_E_EPHY_MII_IO_EN |
+ AC200_EPHY_E_LNK_LED_IO_EN |
+ AC200_EPHY_E_SPD_LED_IO_EN |
+ AC200_EPHY_E_DPX_LED_IO_EN);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(ac200->regmap, AC200_EPHY_CTL,
+ AC200_EPHY_LED_POL |
+ AC200_EPHY_CLK_SEL |
+ AC200_EPHY_ADDR(1) |
+ AC200_EPHY_CALIB(calib));
+ if (ret)
+ return ret;
+
+ ret = phy_driver_register(priv->ephy, THIS_MODULE);
+ if (ret) {
+ dev_err(dev, "Unable to register phy\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ac200_ephy_remove(struct platform_device *pdev)
+{
+ struct ac200_ephy_dev *priv = platform_get_drvdata(pdev);
+
+ phy_driver_unregister(priv->ephy);
+
+ regmap_write(priv->regmap, AC200_EPHY_CTL, AC200_EPHY_SHUTDOWN);
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1, 0);
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0, 0);
+
+ return 0;
+}
+
+static const struct of_device_id ac200_ephy_match[] = {
+ { .compatible = "x-powers,ac200-ephy" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ac200_ephy_match);
+
+static struct platform_driver ac200_ephy_driver = {
+ .probe = ac200_ephy_probe,
+ .remove = ac200_ephy_remove,
+ .driver = {
+ .name = "ac200-ephy",
+ .of_match_table = ac200_ephy_match,
+ },
+};
+module_platform_driver(ac200_ephy_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("AC200 Ethernet PHY driver");
+MODULE_LICENSE("GPL");

View File

@ -1,7 +1,7 @@
From 70ad6a66d55ec76f7a0595b7c1bc94bca11dd289 Mon Sep 17 00:00:00 2001
From 91c70ea17b58c9205c35cd43a3dd8266bbe035b1 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Mon, 25 May 2020 19:06:07 +0200
Subject: [PATCH 1/2] wip: H6 deinterlace
Subject: [PATCH 40/44] wip: H6 deinterlace
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
@ -15,11 +15,9 @@ Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
create mode 100644 drivers/media/platform/sunxi/sun50i-di/sun50i-di.c
create mode 100644 drivers/media/platform/sunxi/sun50i-di/sun50i-di.h
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index c57ee78fa99d..0d3b25d96b10 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -495,6 +495,19 @@ config VIDEO_QCOM_VENUS
@@ -510,6 +510,19 @@ config VIDEO_QCOM_VENUS
on various Qualcomm SoCs.
To compile this driver as a module choose m here.
@ -39,8 +37,6 @@ index c57ee78fa99d..0d3b25d96b10 100644
config VIDEO_SUN8I_DEINTERLACE
tristate "Allwinner Deinterlace driver"
depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
index fc537c9f5ca9..b28f3b15329f 100644
--- a/drivers/media/platform/sunxi/Makefile
+++ b/drivers/media/platform/sunxi/Makefile
@@ -3,4 +3,5 @@
@ -49,17 +45,11 @@ index fc537c9f5ca9..b28f3b15329f 100644
obj-y += sun8i-di/
+obj-y += sun50i-di/
obj-y += sun8i-rotate/
diff --git a/drivers/media/platform/sunxi/sun50i-di/Makefile b/drivers/media/platform/sunxi/sun50i-di/Makefile
new file mode 100644
index 000000000000..225b3b808069
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun50i-di/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VIDEO_SUN50I_DEINTERLACE) += sun50i-di.o
diff --git a/drivers/media/platform/sunxi/sun50i-di/sun50i-di.c b/drivers/media/platform/sunxi/sun50i-di/sun50i-di.c
new file mode 100644
index 000000000000..f6b706fb1a9a
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun50i-di/sun50i-di.c
@@ -0,0 +1,1134 @@
@ -1197,9 +1187,6 @@ index 000000000000..f6b706fb1a9a
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner Deinterlace driver");
diff --git a/drivers/media/platform/sunxi/sun50i-di/sun50i-di.h b/drivers/media/platform/sunxi/sun50i-di/sun50i-di.h
new file mode 100644
index 000000000000..8cb19955ef06
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun50i-di/sun50i-di.h
@@ -0,0 +1,172 @@
@ -1375,6 +1362,3 @@ index 000000000000..8cb19955ef06
+};
+
+#endif
--
2.27.0

View File

@ -1,18 +1,16 @@
From 559f5716ee5e45e87e3bb7f7e5ded5c6116d194b Mon Sep 17 00:00:00 2001
From c009b3b707bbde30fa6ff49ca3075160524ea7b9 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Tue, 26 May 2020 20:08:27 +0200
Subject: [PATCH 2/2] arm64: dts: h6 deinterlace
Subject: [PATCH 41/44] arm64: dts: h6 deinterlace
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 78b1361dfbb9..d45893b7b7b8 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -152,6 +152,17 @@ mixer0_out_tcon_top_mixer0: endpoint {
@@ -153,6 +153,17 @@
};
};
@ -30,6 +28,3 @@ index 78b1361dfbb9..d45893b7b7b8 100644
video-codec@1c0e000 {
compatible = "allwinner,sun50i-h6-video-engine";
reg = <0x01c0e000 0x2000>;
--
2.27.0

View File

@ -0,0 +1,50 @@
From b10b474925447933bf1d718e6d064190b15b56d9 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Thu, 14 Jan 2021 19:26:03 +0100
Subject: [PATCH 42/44] ASoC: sun4i-i2s: Add parenthesis around macro arguments
Several macro arguments are not put inside parenthesis, which may cause
subtle issues.
Fix those macros.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
sound/soc/sunxi/sun4i-i2s.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -116,16 +116,16 @@
#define SUN8I_I2S_CHAN_CFG_REG 0x30
#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4)
-#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) ((chan - 1) << 4)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) (((chan) - 1) << 4)
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
-#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) ((chan) - 1)
#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
-#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12)
+#define SUN8I_I2S_TX_CHAN_OFFSET(offset) ((offset) << 12)
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
-#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4)
+#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << (num_chan)) - 1) << 4)
#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54
#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58
@@ -134,9 +134,9 @@
#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20)
#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20)
#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16)
-#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16)
+#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) (((chan) - 1) << 16)
#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0)
-#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1))
+#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << (num_chan)) - 1))
#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44
#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48

View File

@ -0,0 +1,288 @@
From a19b428a02224e0e01fff4738bbf0632942d18a1 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Fri, 15 Jan 2021 00:13:54 +0100
Subject: [PATCH 43/44] WIP: I2S multi channel
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
sound/soc/sunxi/sun4i-i2s.c | 137 +++++++++++++++++++++++++-----------
1 file changed, 97 insertions(+), 40 deletions(-)
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -23,7 +23,7 @@
#define SUN4I_I2S_CTRL_REG 0x00
#define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
-#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
+#define SUN4I_I2S_CTRL_SDO_EN(lines) (((1 << (lines)) - 1) << 8)
#define SUN4I_I2S_CTRL_MODE_MASK BIT(5)
#define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5)
#define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
@@ -120,8 +120,8 @@
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) ((chan) - 1)
-#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44
-#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34
+#define SUN8I_I2S_TX_CHAN_MAP_REG(i) (0x44 + 4 * (i))
+#define SUN8I_I2S_TX_CHAN_SEL_REG(i) (0x34 + 4 * (i))
#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12)
#define SUN8I_I2S_TX_CHAN_OFFSET(offset) ((offset) << 12)
#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4)
@@ -138,8 +138,8 @@
#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0)
#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << (num_chan)) - 1))
-#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG 0x44
-#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG 0x48
+#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(i) (0x44 + 8 * (i))
+#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(i) (0x48 + 8 * (i))
#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64
#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68
@@ -189,7 +189,7 @@ struct sun4i_i2s_quirks {
* @slots: channels per frame + padding slots, regardless of format
* @slot_width: bits per sample + padding bits, regardless of format
*/
- int (*set_chan_cfg)(const struct sun4i_i2s *i2s,
+ int (*set_chan_cfg)(struct sun4i_i2s *i2s,
unsigned int channels, unsigned int slots,
unsigned int slot_width);
int (*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt);
@@ -205,6 +205,7 @@ struct sun4i_i2s {
unsigned int mclk_freq;
unsigned int slots;
unsigned int slot_width;
+ unsigned int lines;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
@@ -445,7 +446,7 @@ static int sun8i_i2s_get_sr_wss(unsigned
return -EINVAL;
}
-static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+static int sun4i_i2s_set_chan_cfg(struct sun4i_i2s *i2s,
unsigned int channels, unsigned int slots,
unsigned int slot_width)
{
@@ -464,20 +465,42 @@ static int sun4i_i2s_set_chan_cfg(const
return 0;
}
-static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+static int sun8i_i2s_set_chan_cfg(struct sun4i_i2s *i2s,
unsigned int channels, unsigned int slots,
unsigned int slot_width)
{
- unsigned int lrck_period;
+ unsigned int lrck_period, val;
+ int i;
+
+ i2s->lines = (channels + 1) / 2;
+
+ /* Enable the required output lines */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
+ SUN4I_I2S_CTRL_SDO_EN(i2s->lines));
/* Map the channels for playback and capture */
- regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG(0), 0x76543210);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG(1), 0x32);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG(2), 0x54);
+ regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG(3), 0x76);
regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
/* Configure the channels */
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN4I_I2S_CHAN_SEL_MASK,
- SUN4I_I2S_CHAN_SEL(channels));
+ for (i = 0; i < 4; i++) {
+ if (channels <= i * 2)
+ val = 0;
+ else if (channels == i * 2 + 1)
+ val = 1;
+ else
+ val = 2;
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG(i),
+ SUN4I_I2S_CHAN_SEL_MASK |
+ SUN8I_I2S_TX_CHAN_EN_MASK,
+ SUN4I_I2S_CHAN_SEL(val) |
+ SUN8I_I2S_TX_CHAN_EN(val));
+ }
+
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
SUN4I_I2S_CHAN_SEL_MASK,
SUN4I_I2S_CHAN_SEL(channels));
@@ -509,29 +532,47 @@ static int sun8i_i2s_set_chan_cfg(const
SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN8I_I2S_TX_CHAN_EN_MASK,
- SUN8I_I2S_TX_CHAN_EN(channels));
-
return 0;
}
-static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
+static int sun50i_h6_i2s_set_chan_cfg(struct sun4i_i2s *i2s,
unsigned int channels, unsigned int slots,
unsigned int slot_width)
{
- unsigned int lrck_period;
+ unsigned int lrck_period, val;
+ int i;
+
+ i2s->lines = (channels + 1) / 2;
+
+ /* Enable the required output lines */
+ regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
+ SUN4I_I2S_CTRL_SDO_EN_MASK,
+ SUN4I_I2S_CTRL_SDO_EN(i2s->lines));
/* Map the channels for playback and capture */
- regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0xFEDCBA98);
- regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x76543210);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(1), 0x32);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(2), 0x54);
+ regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(3), 0x76);
regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
/* Configure the channels */
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
- SUN50I_H6_I2S_TX_CHAN_SEL(channels));
+ for (i = 0; i < 4; i++) {
+ if (channels <= i * 2)
+ val = 0;
+ else if (channels == i * 2 + 1)
+ val = 1;
+ else
+ val = 2;
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG(i),
+ SUN50I_H6_I2S_TX_CHAN_SEL_MASK |
+ SUN50I_H6_I2S_TX_CHAN_EN_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL(val) |
+ SUN50I_H6_I2S_TX_CHAN_EN(val));
+ }
+
regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
SUN50I_H6_I2S_TX_CHAN_SEL(channels));
@@ -563,10 +604,6 @@ static int sun50i_h6_i2s_set_chan_cfg(co
SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN50I_H6_I2S_TX_CHAN_EN_MASK,
- SUN50I_H6_I2S_TX_CHAN_EN(channels));
-
return 0;
}
@@ -711,6 +748,7 @@ static int sun8i_i2s_set_soc_fmt(const s
{
u32 mode, val;
u8 offset;
+ int i;
/*
* DAI clock polarity
@@ -778,9 +816,10 @@ static int sun8i_i2s_set_soc_fmt(const s
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
SUN8I_I2S_CTRL_MODE_MASK, mode);
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN8I_I2S_TX_CHAN_OFFSET_MASK,
- SUN8I_I2S_TX_CHAN_OFFSET(offset));
+ for (i = 0; i < 4; i++)
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG(i),
+ SUN8I_I2S_TX_CHAN_OFFSET_MASK,
+ SUN8I_I2S_TX_CHAN_OFFSET(offset));
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
SUN8I_I2S_TX_CHAN_OFFSET_MASK,
SUN8I_I2S_TX_CHAN_OFFSET(offset));
@@ -818,6 +857,7 @@ static int sun50i_h6_i2s_set_soc_fmt(con
{
u32 mode, val;
u8 offset;
+ int i;
/*
* DAI clock polarity
@@ -885,9 +925,10 @@ static int sun50i_h6_i2s_set_soc_fmt(con
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
SUN8I_I2S_CTRL_MODE_MASK, mode);
- regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
- SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
- SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
+ for (i = 0; i < 4; i++)
+ regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG(i),
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
+ SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
@@ -1198,8 +1239,14 @@ static const struct reg_default sun8i_i2
{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
- { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
- { SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(0), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(1), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(2), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(3), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_MAP_REG(0), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_MAP_REG(1), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_MAP_REG(2), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_MAP_REG(3), 0x00000000 },
{ SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 },
{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
};
@@ -1212,9 +1259,18 @@ static const struct reg_default sun50i_h
{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
- { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
- { SUN50I_H6_I2S_TX_CHAN_MAP0_REG, 0x00000000 },
- { SUN50I_H6_I2S_TX_CHAN_MAP1_REG, 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(0), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(1), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(2), 0x00000000 },
+ { SUN8I_I2S_TX_CHAN_SEL_REG(3), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(1), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(1), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(2), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(2), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(3), 0x00000000 },
+ { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(3), 0x00000000 },
{ SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
{ SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
{ SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
@@ -1287,7 +1343,7 @@ static int sun4i_i2s_runtime_resume(stru
/* Enable the first output line */
regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
SUN4I_I2S_CTRL_SDO_EN_MASK,
- SUN4I_I2S_CTRL_SDO_EN(0));
+ SUN4I_I2S_CTRL_SDO_EN(i2s->lines));
ret = clk_prepare_enable(i2s->mod_clk);
if (ret) {
@@ -1529,6 +1585,7 @@ static int sun4i_i2s_probe(struct platfo
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
i2s->capture_dma_data.maxburst = 8;
+ i2s->lines = 1;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {

View File

@ -1,16 +1,25 @@
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 8aa2befc..d3d70eac 100644
From d0428e1d4b2a1a3d640f6052646e0f8ca7fc2d53 Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@siol.net>
Date: Sat, 16 Jan 2021 10:57:58 +0100
Subject: [PATCH 44/44] HACK: h3/h5: Add HDMI sound card
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/boot/dts/sunxi-h3-h5.dtsi | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -53,6 +53,23 @@
#address-cells = <1>;
#size-cells = <1>;
@@ -77,6 +77,24 @@
};
};
+ sound_hdmi: sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,name = "allwinner-hdmi";
+ simple-audio-card,mclk-fs = <128>;
+ simple-audio-card,frame-inversion;
+
+ simple-audio-card,codec {
+ sound-dai = <&hdmi>;
@ -26,27 +35,15 @@ index 8aa2befc..d3d70eac 100644
clocks {
#address-cells = <1>;
#size-cells = <1>;
@@ -631,6 +648,19 @@
status = "disabled";
@@ -672,7 +690,6 @@
dmas = <&dma 27>;
resets = <&ccu RST_BUS_I2S2>;
dma-names = "tx";
- status = "disabled";
};
+ i2s2: i2s@1c22800 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-h3-i2s";
+ reg = <0x01c22800 0x400>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_I2S2>, <&ccu CLK_I2S2>;
+ clock-names = "apb", "mod";
+ dmas = <&dma 27>;
+ resets = <&ccu RST_BUS_I2S2>;
+ dma-names = "tx";
+ allwinner,playback-channels = <8>;
+ };
+
codec: codec@1c22c00 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun8i-h3-codec";
@@ -110,6 +126,7 @@
@@ -806,6 +823,7 @@
};
hdmi: hdmi@1ee0000 {

View File

@ -11,7 +11,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -388,6 +388,7 @@
@@ -406,6 +406,7 @@
reg = <0x01c20000 0x400>;
clocks = <&osc24M>, <&rtc 0>;
clock-names = "hosc", "losc";
@ -19,7 +19,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -852,6 +853,7 @@
@@ -883,6 +884,7 @@
clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
<&ccu CLK_PLL_PERIPH0>;
clock-names = "hosc", "losc", "iosc", "pll-periph";

View File

@ -19,7 +19,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -1212,6 +1213,7 @@
@@ -1226,6 +1227,7 @@
clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
<&ccu CLK_PLL_PERIPH0>;
clock-names = "hosc", "losc", "iosc", "pll-periph";

View File

@ -11,7 +11,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -230,6 +230,7 @@
@@ -241,6 +241,7 @@
reg = <0x03001000 0x1000>;
clocks = <&osc24M>, <&rtc 0>, <&rtc 2>;
clock-names = "hosc", "losc", "iosc";
@ -19,7 +19,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -894,6 +895,7 @@
@@ -918,6 +919,7 @@
clocks = <&osc24M>, <&rtc 0>, <&rtc 2>,
<&ccu CLK_PLL_PERIPH0>;
clock-names = "hosc", "losc", "iosc", "pll-periph";

View File

@ -15,7 +15,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -847,6 +847,15 @@
@@ -878,6 +878,15 @@
#clock-cells = <1>;
};

View File

@ -17,7 +17,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -840,8 +840,9 @@
@@ -871,8 +871,9 @@
rtc: rtc@1f00000 {
/* compatible is in per SoC .dtsi file */
reg = <0x01f00000 0x400>;
@ -29,7 +29,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
clock-output-names = "osc32k", "osc32k-out", "iosc";
clocks = <&osc32k>;
#clock-cells = <1>;
@@ -877,7 +878,8 @@
@@ -908,7 +909,8 @@
clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>;
clock-names = "apb", "ir";
resets = <&r_ccu RST_APB0_IR>;
@ -39,7 +39,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
reg = <0x01f02000 0x400>;
status = "disabled";
};
@@ -898,7 +900,8 @@
@@ -929,7 +931,8 @@
r_pio: pinctrl@1f02c00 {
compatible = "allwinner,sun8i-h3-r-pinctrl";
reg = <0x01f02c00 0x400>;

View File

@ -17,7 +17,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -1191,8 +1191,9 @@
@@ -1205,8 +1205,9 @@
compatible = "allwinner,sun50i-a64-rtc",
"allwinner,sun8i-h3-rtc";
reg = <0x01f00000 0x400>;
@ -29,7 +29,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
clock-output-names = "osc32k", "osc32k-out", "iosc";
clocks = <&osc32k>;
#clock-cells = <1>;
@@ -1243,7 +1244,8 @@
@@ -1257,7 +1258,8 @@
clocks = <&r_ccu CLK_APB0_IR>, <&r_ccu CLK_IR>;
clock-names = "apb", "ir";
resets = <&r_ccu RST_APB0_IR>;
@ -39,7 +39,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
pinctrl-names = "default";
pinctrl-0 = <&r_ir_rx_pin>;
status = "disabled";
@@ -1263,7 +1265,8 @@
@@ -1277,7 +1279,8 @@
r_pio: pinctrl@1f02c00 {
compatible = "allwinner,sun50i-a64-r-pinctrl";
reg = <0x01f02c00 0x400>;

View File

@ -13,7 +13,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -941,17 +941,17 @@
@@ -965,17 +965,17 @@
};
r_ir: ir@7040000 {

View File

@ -17,7 +17,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -883,8 +883,9 @@
@@ -907,8 +907,9 @@
rtc: rtc@7000000 {
compatible = "allwinner,sun50i-h6-rtc";
reg = <0x07000000 0x400>;
@ -29,7 +29,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
clock-output-names = "osc32k", "osc32k-out", "iosc";
#clock-cells = <1>;
};
@@ -920,8 +921,9 @@
@@ -944,8 +945,9 @@
r_pio: pinctrl@7022000 {
compatible = "allwinner,sun50i-h6-r-pinctrl";
reg = <0x07022000 0x400>;
@ -41,7 +41,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&rtc 0>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
@@ -944,7 +946,8 @@
@@ -968,7 +970,8 @@
compatible = "allwinner,sun50i-h6-ir",
"allwinner,sun6i-a31-ir";
reg = <0x07040000 0x400>;

Some files were not shown because too many files have changed in this diff Show More