mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-29 13:46:49 +00:00
Allwinner: Remove support for A20
This commit is contained in:
parent
a5be43f45c
commit
cf5e056881
@ -1,34 +0,0 @@
|
||||
#
|
||||
# Configuration for HDMI
|
||||
#
|
||||
|
||||
<confdir:pcm/hdmi.conf>
|
||||
|
||||
sun4i-hdmi.pcm.hdmi.0 {
|
||||
@args [ CARD AES0 AES1 AES2 AES3 ]
|
||||
@args.CARD { type string }
|
||||
@args.AES0 { type integer }
|
||||
@args.AES1 { type integer }
|
||||
@args.AES2 { type integer }
|
||||
@args.AES3 { type integer }
|
||||
type hooks
|
||||
slave.pcm {
|
||||
type hw
|
||||
card $CARD
|
||||
device 0
|
||||
}
|
||||
hooks.0 {
|
||||
type ctl_elems
|
||||
hook_args [
|
||||
{
|
||||
interface MIXER
|
||||
name "IEC958 Playback Default"
|
||||
lock true
|
||||
preserve true
|
||||
optional true
|
||||
value [ $AES0 $AES1 $AES2 $AES3 ]
|
||||
}
|
||||
]
|
||||
}
|
||||
hint.device 0
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
################################################################################
|
||||
# setup system defaults
|
||||
################################################################################
|
||||
|
||||
# The TARGET_CPU variable controls which processor should be targeted for
|
||||
# generated code.
|
||||
case $TARGET_ARCH in
|
||||
arm)
|
||||
# TARGET_CPU:
|
||||
# arm2 arm250 arm3 arm6 arm60 arm600 arm610 arm620 arm7 arm7m arm7d
|
||||
# arm7dm arm7di arm7dmi arm70 arm700 arm700i arm710 arm710c
|
||||
# arm7100 arm720 arm7500 arm7500fe arm7tdmi arm7tdmi-s arm710t
|
||||
# arm720t arm740t strongarm strongarm110 strongarm1100
|
||||
# strongarm1110 arm8 arm810 arm9 arm9e arm920 arm920t arm922t
|
||||
# arm946e-s arm966e-s arm968e-s arm926ej-s arm940t arm9tdmi
|
||||
# arm10tdmi arm1020t arm1026ej-s arm10e arm1020e arm1022e
|
||||
# arm1136j-s arm1136jf-s mpcore mpcorenovfp arm1156t2-s
|
||||
# arm1176jz-s arm1176jzf-s cortex-a8 cortex-a9 cortex-r4
|
||||
# cortex-r4f cortex-m3 cortex-m1 xscale iwmmxt iwmmxt2 ep9312.
|
||||
TARGET_CPU="cortex-a7"
|
||||
|
||||
# TARGET_FLOAT:
|
||||
# Specifies which floating-point ABI to use. Permissible values are:
|
||||
# soft hard
|
||||
TARGET_FLOAT="hard"
|
||||
|
||||
# TARGET_FPU:
|
||||
# This specifies what floating point hardware (or hardware emulation) is
|
||||
# available on the target. Permissible names are:
|
||||
# fpa fpe2 fpe3 maverick vfp vfpv3 vfpv3-fp16 vfpv3-d16 vfpv3-d16-fp16
|
||||
# vfpv3xd vfpv3xd-fp16 neon neon-fp16 vfpv4 vfpv4-d16 fpv4-sp-d16
|
||||
# neon-vfpv4.
|
||||
TARGET_FPU="neon-vfpv4"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Kernel target
|
||||
KERNEL_TARGET="zImage"
|
||||
|
||||
# OpenGL-ES implementation to use (no / bcm2835-driver / gpu-viv-bin-mx6q)
|
||||
OPENGLES="mesa"
|
||||
|
||||
# Mali GPU family
|
||||
MALI_FAMILY="400"
|
||||
|
||||
# KODI Player implementation to use (default / bcm2835-driver / libfslvpuwrap)
|
||||
KODIPLAYER_DRIVER="$OPENGLES"
|
||||
|
||||
# set the addon project
|
||||
ADDON_PROJECT="ARMv7"
|
@ -1,193 +0,0 @@
|
||||
From ae3215d37ca2a55642bcae6c83c3612e26275711 Mon Sep 17 00:00:00 2001
|
||||
From: Luc Verhaegen <libv@skynet.be>
|
||||
Date: Thu, 8 Aug 2019 16:27:37 +0200
|
||||
Subject: [PATCH] kms:sunxi: add engine->crtc_mode_set() hook
|
||||
|
||||
This exposes both shortcomings in universal planes, and the superfluous
|
||||
intermediate structure of _engine.
|
||||
|
||||
Our backends are half the conceptual old-skool style CRTC, and half the
|
||||
sequencer/composer. It does not need to have any layer enabled or any
|
||||
buffer attached to do something useful, it can just show a background
|
||||
colour. Our 4 main layers are fully independent and can be ordered
|
||||
(almost) at will. There is no primary layer.
|
||||
|
||||
Universal planes still asume that there is a primary layer. And also do
|
||||
limited checking on whether this actually true.
|
||||
|
||||
The sun4i driver has, for some reason, an _engine struct in between,
|
||||
that serves no purpose other than to provide separation where no
|
||||
separation is needed, and it is clear in several cases that this
|
||||
separation has holes in it. It also is a psychological barrier for
|
||||
exposing things as the hardware sees it.
|
||||
|
||||
So instead of quickly bolting up some code to set the crtc width and
|
||||
height in the backend, it was deferred to setting the primary plane.
|
||||
|
||||
So while KMS assumes that there is a primary plane, it never enforces
|
||||
the primary plane to be the same dimensions as the CRTC.
|
||||
|
||||
So one is able to set the faux primary plane to whatever dimensions one
|
||||
likes, which then has the backend set to those dimensions, which then
|
||||
trips up our whole setup...
|
||||
|
||||
A very avoidable problem, on multiple fronts.
|
||||
|
||||
Also, we set interlacing with _every_ plane format set. This while this
|
||||
conceptually belongs to the CRTC. The fact that the information comes
|
||||
from the modeline should've tipped people off that this was wrong.
|
||||
|
||||
Let's at least get rid of this engine struct in future, and have direct
|
||||
code dependencies between modules, so that at least this psychological
|
||||
barrier disappears.
|
||||
|
||||
Signed-off-by: Luc Verhaegen <libv@skynet.be>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/sun4i_backend.c | 43 ++++++++++++++-------------
|
||||
drivers/gpu/drm/sun4i/sun4i_crtc.c | 2 ++
|
||||
drivers/gpu/drm/sun4i/sun8i_mixer.c | 7 +++++
|
||||
drivers/gpu/drm/sun4i/sunxi_engine.h | 7 +++++
|
||||
4 files changed, 39 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
|
||||
index 606b33a28be5..4d7a33d0f77f 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
|
||||
@@ -164,6 +164,28 @@ bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int sun4i_backend_crtc_mode_set(struct sunxi_engine *engine,
|
||||
+ struct drm_display_mode *mode)
|
||||
+{
|
||||
+ DRM_DEBUG_DRIVER("%s(DEBE%d);\n", __func__, engine->id);
|
||||
+
|
||||
+ regmap_write(engine->regs, SUN4I_BACKEND_DISSIZE_REG,
|
||||
+ SUN4I_BACKEND_DISSIZE(mode->crtc_hdisplay,
|
||||
+ mode->crtc_vdisplay));
|
||||
+
|
||||
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
||||
+ DRM_DEBUG_DRIVER("%s(DEBE%d): Enabling interlacing.\n",
|
||||
+ __func__, engine->id);
|
||||
+ regmap_update_bits(engine->regs, SUN4I_BACKEND_MODCTL_REG,
|
||||
+ SUN4I_BACKEND_MODCTL_ITLMOD_EN,
|
||||
+ SUN4I_BACKEND_MODCTL_ITLMOD_EN);
|
||||
+ } else
|
||||
+ regmap_update_bits(engine->regs, SUN4I_BACKEND_MODCTL_REG,
|
||||
+ SUN4I_BACKEND_MODCTL_ITLMOD_EN, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
|
||||
int layer, struct drm_plane *plane)
|
||||
{
|
||||
@@ -171,14 +193,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
|
||||
|
||||
DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
|
||||
|
||||
- if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
|
||||
- DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
|
||||
- state->crtc_w, state->crtc_h);
|
||||
- regmap_write(backend->engine.regs, SUN4I_BACKEND_DISSIZE_REG,
|
||||
- SUN4I_BACKEND_DISSIZE(state->crtc_w,
|
||||
- state->crtc_h));
|
||||
- }
|
||||
-
|
||||
/* Set height and width */
|
||||
DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
|
||||
state->crtc_w, state->crtc_h);
|
||||
@@ -325,24 +339,12 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
|
||||
{
|
||||
struct drm_plane_state *state = plane->state;
|
||||
struct drm_framebuffer *fb = state->fb;
|
||||
- bool interlaced = false;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
/* Clear the YUV mode */
|
||||
regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
|
||||
SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
|
||||
-
|
||||
- if (plane->state->crtc)
|
||||
- interlaced = plane->state->crtc->state->adjusted_mode.flags
|
||||
- & DRM_MODE_FLAG_INTERLACE;
|
||||
-
|
||||
- regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
|
||||
- SUN4I_BACKEND_MODCTL_ITLMOD_EN,
|
||||
- interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
|
||||
-
|
||||
- DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
|
||||
- interlaced ? "on" : "off");
|
||||
|
||||
if (fb->format->is_yuv)
|
||||
return sun4i_backend_update_yuv_format(backend, layer, plane);
|
||||
@@ -920,6 +922,7 @@ static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
|
||||
.apply_color_correction = sun4i_backend_apply_color_correction,
|
||||
.disable_color_correction = sun4i_backend_disable_color_correction,
|
||||
.vblank_quirk = sun4i_backend_vblank_quirk,
|
||||
+ .crtc_mode_set = sun4i_backend_crtc_mode_set,
|
||||
};
|
||||
|
||||
static struct regmap_config sun4i_backend_regmap_config = {
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
|
||||
index 9d8504f813a4..cc569d0ec49c 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
|
||||
@@ -138,8 +138,10 @@ static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
||||
struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
struct drm_encoder *encoder = sun4i_crtc_get_encoder(crtc);
|
||||
struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
|
||||
+ struct sunxi_engine *engine = scrtc->engine;
|
||||
|
||||
sun4i_tcon_mode_set(scrtc->tcon, encoder, mode);
|
||||
+ engine->ops->crtc_mode_set(engine, mode);
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
||||
index c2eedf58bf4b..2d6c7c4501b8 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
|
||||
@@ -307,9 +307,16 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
|
||||
return planes;
|
||||
}
|
||||
|
||||
+static int sun8i_mixer_crtc_mode_set(struct sunxi_engine *engine,
|
||||
+ struct drm_display_mode *mode)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static const struct sunxi_engine_ops sun8i_engine_ops = {
|
||||
.commit = sun8i_mixer_commit,
|
||||
.layers_init = sun8i_layers_init,
|
||||
+ .crtc_mode_set = sun8i_mixer_crtc_mode_set,
|
||||
};
|
||||
|
||||
static struct regmap_config sun8i_mixer_regmap_config = {
|
||||
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
|
||||
index 548710a936d5..1f3aaef2cabc 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
|
||||
@@ -9,6 +9,7 @@
|
||||
struct drm_plane;
|
||||
struct drm_device;
|
||||
struct drm_crtc_state;
|
||||
+struct drm_display_mode;
|
||||
|
||||
struct sunxi_engine;
|
||||
|
||||
@@ -108,6 +109,12 @@ struct sunxi_engine_ops {
|
||||
* This function is optional.
|
||||
*/
|
||||
void (*vblank_quirk)(struct sunxi_engine *engine);
|
||||
+
|
||||
+ /*
|
||||
+ * Sets amongst others, CRTC dimensions, and interlacing.
|
||||
+ */
|
||||
+ int (*crtc_mode_set)(struct sunxi_engine *engine,
|
||||
+ struct drm_display_mode *mode);
|
||||
};
|
||||
|
||||
/**
|
@ -1,506 +0,0 @@
|
||||
Subject: [2/2] drm: sun4i: hdmi: Add support for sun4i HDMI encoder audio
|
||||
From: Stefan Mavrodiev <stefan@olimex.com>
|
||||
Date: Fri, 10 Jan 2020 16:11:40 +0200
|
||||
|
||||
Add HDMI audio support for the sun4i-hdmi encoder, used on
|
||||
the older Allwinner chips - A10, A20, A31.
|
||||
|
||||
Most of the code is based on the BSP implementation. In it
|
||||
dditional formats are supported (S20_3LE and S24_LE), however
|
||||
there where some problems with them and only S16_LE is left.
|
||||
|
||||
Signed-off-by: Stefan Mavrodiev <stefan@olimex.com>
|
||||
---
|
||||
drivers/gpu/drm/sun4i/Kconfig | 1 +
|
||||
drivers/gpu/drm/sun4i/Makefile | 1 +
|
||||
drivers/gpu/drm/sun4i/sun4i_hdmi.h | 30 ++
|
||||
drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c | 375 +++++++++++++++++++++++
|
||||
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 4 +
|
||||
5 files changed, 411 insertions(+)
|
||||
create mode 100644 drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c
|
||||
|
||||
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
|
||||
index 37e90e42943f..192b732b10cd 100644
|
||||
--- a/drivers/gpu/drm/sun4i/Kconfig
|
||||
+++ b/drivers/gpu/drm/sun4i/Kconfig
|
||||
@@ -19,6 +19,7 @@ if DRM_SUN4I
|
||||
config DRM_SUN4I_HDMI
|
||||
tristate "Allwinner A10 HDMI Controller Support"
|
||||
default DRM_SUN4I
|
||||
+ select SND_PCM_ELD
|
||||
help
|
||||
Choose this option if you have an Allwinner SoC with an HDMI
|
||||
controller.
|
||||
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
|
||||
index 0d04f2447b01..e2d82b451c36 100644
|
||||
--- a/drivers/gpu/drm/sun4i/Makefile
|
||||
+++ b/drivers/gpu/drm/sun4i/Makefile
|
||||
@@ -5,6 +5,7 @@ sun4i-frontend-y += sun4i_frontend.o
|
||||
sun4i-drm-y += sun4i_drv.o
|
||||
sun4i-drm-y += sun4i_framebuffer.o
|
||||
|
||||
+sun4i-drm-hdmi-y += sun4i_hdmi_audio.o
|
||||
sun4i-drm-hdmi-y += sun4i_hdmi_ddc_clk.o
|
||||
sun4i-drm-hdmi-y += sun4i_hdmi_enc.o
|
||||
sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi.h b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
|
||||
index 7ad3f06c127e..456964e681b0 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi.h
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi.h
|
||||
@@ -42,7 +42,32 @@
|
||||
#define SUN4I_HDMI_VID_TIMING_POL_VSYNC BIT(1)
|
||||
#define SUN4I_HDMI_VID_TIMING_POL_HSYNC BIT(0)
|
||||
|
||||
+#define SUN4I_HDMI_AUDIO_CTRL_REG 0x040
|
||||
+#define SUN4I_HDMI_AUDIO_CTRL_ENABLE BIT(31)
|
||||
+#define SUN4I_HDMI_AUDIO_CTRL_RESET BIT(30)
|
||||
+
|
||||
+#define SUN4I_HDMI_AUDIO_FMT_REG 0x048
|
||||
+#define SUN4I_HDMI_AUDIO_FMT_SRC BIT(31)
|
||||
+#define SUN4I_HDMI_AUDIO_FMT_LAYOUT BIT(3)
|
||||
+#define SUN4I_HDMI_AUDIO_FMT_CH_CFG(n) (n - 1)
|
||||
+#define SUN4I_HDMI_AUDIO_FMT_CH_CFG_MASK GENMASK(2, 0)
|
||||
+
|
||||
+#define SUN4I_HDMI_AUDIO_PCM_REG 0x4c
|
||||
+#define SUN4I_HDMI_AUDIO_PCM_CH_MAP(n, m) ((m - 1) << (n * 4))
|
||||
+#define SUN4I_HDMI_AUDIO_PCM_CH_MAP_MASK(n) (GENMASK(2, 0) << (n * 4))
|
||||
+
|
||||
+#define SUN4I_HDMI_AUDIO_CTS_REG 0x050
|
||||
+#define SUN4I_HDMI_AUDIO_CTS(n) (n & GENMASK(19, 0))
|
||||
+
|
||||
+#define SUN4I_HDMI_AUDIO_N_REG 0x054
|
||||
+#define SUN4I_HDMI_AUDIO_N(n) (n & GENMASK(19, 0))
|
||||
+
|
||||
+#define SUN4I_HDMI_AUDIO_STAT0_REG 0x58
|
||||
+#define SUN4I_HDMI_AUDIO_STAT0_FREQ(n) (n << 24)
|
||||
+#define SUN4I_HDMI_AUDIO_STAT0_FREQ_MASK GENMASK(27, 24)
|
||||
+
|
||||
#define SUN4I_HDMI_AVI_INFOFRAME_REG(n) (0x080 + (n))
|
||||
+#define SUN4I_HDMI_AUDIO_INFOFRAME_REG(n) (0x0a0 + (n))
|
||||
|
||||
#define SUN4I_HDMI_PAD_CTRL0_REG 0x200
|
||||
#define SUN4I_HDMI_PAD_CTRL0_BIASEN BIT(31)
|
||||
@@ -283,9 +308,13 @@ struct sun4i_hdmi {
|
||||
struct regmap_field *field_ddc_sda_en;
|
||||
struct regmap_field *field_ddc_sck_en;
|
||||
|
||||
+ u8 hdmi_audio_channels;
|
||||
+
|
||||
struct sun4i_drv *drv;
|
||||
|
||||
bool hdmi_monitor;
|
||||
+ bool hdmi_audio;
|
||||
+
|
||||
struct cec_adapter *cec_adap;
|
||||
|
||||
const struct sun4i_hdmi_variant *variant;
|
||||
@@ -294,5 +323,6 @@ struct sun4i_hdmi {
|
||||
int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *clk);
|
||||
int sun4i_tmds_create(struct sun4i_hdmi *hdmi);
|
||||
int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi);
|
||||
+int sun4i_hdmi_audio_create(struct sun4i_hdmi *hdmi);
|
||||
|
||||
#endif /* _SUN4I_HDMI_H_ */
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c
|
||||
new file mode 100644
|
||||
index 000000000000..b6d4199d15ce
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_audio.c
|
||||
@@ -0,0 +1,375 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * Copyright (C) 2020 Olimex Ltd.
|
||||
+ * Author: Stefan Mavrodiev <stefan@olimex.com>
|
||||
+ */
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <linux/dmaengine.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_dma.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <drm/drm_print.h>
|
||||
+
|
||||
+#include <sound/dmaengine_pcm.h>
|
||||
+#include <sound/pcm_drm_eld.h>
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "sun4i_hdmi.h"
|
||||
+
|
||||
+static const struct snd_soc_dapm_widget sun4i_hdmi_audio_widgets[] = {
|
||||
+ SND_SOC_DAPM_OUTPUT("TX"),
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_dapm_route sun4i_hdmi_audio_routes[] = {
|
||||
+ { "TX", NULL, "Playback" },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver sun4i_hdmi_audio_component = {
|
||||
+ .dapm_widgets = sun4i_hdmi_audio_widgets,
|
||||
+ .num_dapm_widgets = ARRAY_SIZE(sun4i_hdmi_audio_widgets),
|
||||
+ .dapm_routes = sun4i_hdmi_audio_routes,
|
||||
+ .num_dapm_routes = ARRAY_SIZE(sun4i_hdmi_audio_routes),
|
||||
+};
|
||||
+
|
||||
+static int sun4i_hdmi_audio_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
|
||||
+ struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
|
||||
+ u32 reg;
|
||||
+ int ret;
|
||||
+
|
||||
+ regmap_write(hdmi->regmap, SUN4I_HDMI_AUDIO_CTRL_REG, 0);
|
||||
+ regmap_write(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_CTRL_REG,
|
||||
+ SUN4I_HDMI_AUDIO_CTRL_RESET);
|
||||
+ ret = regmap_read_poll_timeout(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_CTRL_REG,
|
||||
+ reg, !reg, 100, 50000);
|
||||
+ if (ret < 0) {
|
||||
+ DRM_ERROR("Failed to reset HDMI Audio\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ regmap_write(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_CTRL_REG,
|
||||
+ SUN4I_HDMI_AUDIO_CTRL_ENABLE);
|
||||
+
|
||||
+ return snd_pcm_hw_constraint_eld(substream->runtime,
|
||||
+ hdmi->connector.eld);
|
||||
+}
|
||||
+
|
||||
+static void sun4i_hdmi_audio_shutdown(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
|
||||
+ struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
|
||||
+
|
||||
+ regmap_write(hdmi->regmap, SUN4I_HDMI_AUDIO_CTRL_REG, 0);
|
||||
+}
|
||||
+
|
||||
+static int sun4i_hdmi_setup_audio_infoframes(struct sun4i_hdmi *hdmi)
|
||||
+{
|
||||
+ union hdmi_infoframe frame;
|
||||
+ u8 buffer[14];
|
||||
+ int i, ret;
|
||||
+
|
||||
+ ret = hdmi_audio_infoframe_init(&frame.audio);
|
||||
+ if (ret < 0) {
|
||||
+ DRM_ERROR("Failed to init HDMI audio infoframe\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ frame.audio.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
|
||||
+ frame.audio.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
|
||||
+ frame.audio.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
|
||||
+ frame.audio.channels = hdmi->hdmi_audio_channels;
|
||||
+
|
||||
+ ret = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer));
|
||||
+ if (ret < 0) {
|
||||
+ DRM_ERROR("Failed to pack HDMI audio infoframe\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < sizeof(buffer); i++)
|
||||
+ writeb(buffer[i],
|
||||
+ hdmi->base + SUN4I_HDMI_AUDIO_INFOFRAME_REG(i));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void sun4i_hdmi_audio_set_cts_n(struct sun4i_hdmi *hdmi,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct drm_encoder *encoder = &hdmi->encoder;
|
||||
+ struct drm_crtc *crtc = encoder->crtc;
|
||||
+ const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
|
||||
+ u32 rate = params_rate(params);
|
||||
+ u32 n, cts;
|
||||
+ u64 tmp;
|
||||
+
|
||||
+ /**
|
||||
+ * Calculate Cycle Time Stamp (CTS) and Numerator (N):
|
||||
+ *
|
||||
+ * N = 128 * Samplerate / 1000
|
||||
+ * CTS = (Ftdms * N) / (128 * Samplerate)
|
||||
+ */
|
||||
+
|
||||
+ n = 128 * rate / 1000;
|
||||
+ tmp = (u64)(mode->clock * 1000) * n;
|
||||
+ do_div(tmp, 128 * rate);
|
||||
+ cts = tmp;
|
||||
+
|
||||
+ regmap_write(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_CTS_REG,
|
||||
+ SUN4I_HDMI_AUDIO_CTS(cts));
|
||||
+
|
||||
+ regmap_write(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_N_REG,
|
||||
+ SUN4I_HDMI_AUDIO_N(n));
|
||||
+}
|
||||
+
|
||||
+static int sun4i_hdmi_audio_set_hw_rate(struct sun4i_hdmi *hdmi,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ u32 rate = params_rate(params);
|
||||
+ u32 val;
|
||||
+
|
||||
+ switch (rate) {
|
||||
+ case 44100:
|
||||
+ val = 0x0;
|
||||
+ break;
|
||||
+ case 48000:
|
||||
+ val = 0x2;
|
||||
+ break;
|
||||
+ case 32000:
|
||||
+ val = 0x3;
|
||||
+ break;
|
||||
+ case 88200:
|
||||
+ val = 0x8;
|
||||
+ break;
|
||||
+ case 96000:
|
||||
+ val = 0x9;
|
||||
+ break;
|
||||
+ case 176400:
|
||||
+ val = 0xc;
|
||||
+ break;
|
||||
+ case 192000:
|
||||
+ val = 0xe;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_STAT0_REG,
|
||||
+ SUN4I_HDMI_AUDIO_STAT0_FREQ_MASK,
|
||||
+ SUN4I_HDMI_AUDIO_STAT0_FREQ(val));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int sun4i_hdmi_audio_set_hw_channels(struct sun4i_hdmi *hdmi,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ u32 channels = params_channels(params);
|
||||
+
|
||||
+ if (channels > 8)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ hdmi->hdmi_audio_channels = channels;
|
||||
+
|
||||
+ regmap_update_bits(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_FMT_REG,
|
||||
+ SUN4I_HDMI_AUDIO_FMT_LAYOUT,
|
||||
+ (channels > 2) ? SUN4I_HDMI_AUDIO_FMT_LAYOUT : 0);
|
||||
+
|
||||
+ regmap_update_bits(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_FMT_REG,
|
||||
+ SUN4I_HDMI_AUDIO_FMT_CH_CFG_MASK,
|
||||
+ SUN4I_HDMI_AUDIO_FMT_CH_CFG(channels));
|
||||
+
|
||||
+ regmap_write(hdmi->regmap, SUN4I_HDMI_AUDIO_PCM_REG, 0x76543210);
|
||||
+
|
||||
+ /**
|
||||
+ * If only one channel is required, send the same sample
|
||||
+ * to the sink device as a left and right channel.
|
||||
+ */
|
||||
+ if (channels == 1)
|
||||
+ regmap_update_bits(hdmi->regmap,
|
||||
+ SUN4I_HDMI_AUDIO_PCM_REG,
|
||||
+ SUN4I_HDMI_AUDIO_PCM_CH_MAP_MASK(1),
|
||||
+ SUN4I_HDMI_AUDIO_PCM_CH_MAP(1, 1));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int sun4i_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
|
||||
+ struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = sun4i_hdmi_audio_set_hw_rate(hdmi, params);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = sun4i_hdmi_audio_set_hw_channels(hdmi, params);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ sun4i_hdmi_audio_set_cts_n(hdmi, params);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int sun4i_hdmi_audio_trigger(struct snd_pcm_substream *substream,
|
||||
+ int cmd,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
|
||||
+ struct sun4i_hdmi *hdmi = snd_soc_card_get_drvdata(card);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ ret = sun4i_hdmi_setup_audio_infoframes(hdmi);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops sun4i_hdmi_audio_dai_ops = {
|
||||
+ .startup = sun4i_hdmi_audio_startup,
|
||||
+ .shutdown = sun4i_hdmi_audio_shutdown,
|
||||
+ .hw_params = sun4i_hdmi_audio_hw_params,
|
||||
+ .trigger = sun4i_hdmi_audio_trigger,
|
||||
+};
|
||||
+
|
||||
+static int sun4i_hdmi_audio_dai_probe(struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct snd_dmaengine_dai_dma_data *dma_data;
|
||||
+
|
||||
+ dma_data = devm_kzalloc(dai->dev, sizeof(*dma_data), GFP_KERNEL);
|
||||
+ if (!dma_data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ dma_data->addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
+ dma_data->maxburst = 8;
|
||||
+
|
||||
+ snd_soc_dai_init_dma_data(dai, dma_data, NULL);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct snd_soc_dai_driver sun4i_hdmi_audio_dai = {
|
||||
+ .name = "HDMI",
|
||||
+ .ops = &sun4i_hdmi_audio_dai_ops,
|
||||
+ .probe = sun4i_hdmi_audio_dai_probe,
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 1,
|
||||
+ .channels_max = 8,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_192000,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct snd_pcm_hardware sun4i_hdmi_audio_pcm_hardware = {
|
||||
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID |
|
||||
+ SNDRV_PCM_INFO_PAUSE |
|
||||
+ SNDRV_PCM_INFO_RESUME,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_192000,
|
||||
+ .rate_min = 8000,
|
||||
+ .rate_max = 192000,
|
||||
+ .channels_min = 1,
|
||||
+ .channels_max = 8,
|
||||
+ .buffer_bytes_max = 128 * 1024,
|
||||
+ .period_bytes_min = 4 * 1024,
|
||||
+ .period_bytes_max = 32 * 1024,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = 8,
|
||||
+ .fifo_size = 128,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_dmaengine_pcm_config sun4i_hdmi_audio_pcm_config = {
|
||||
+ .chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "audio-tx",
|
||||
+ .pcm_hardware = &sun4i_hdmi_audio_pcm_hardware,
|
||||
+ .prealloc_buffer_size = 128 * 1024,
|
||||
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
|
||||
+};
|
||||
+
|
||||
+struct snd_soc_card sun4i_hdmi_audio_card = {
|
||||
+ .name = "sun4i-hdmi",
|
||||
+};
|
||||
+
|
||||
+int sun4i_hdmi_audio_create(struct sun4i_hdmi *hdmi)
|
||||
+{
|
||||
+ struct snd_soc_card *card = &sun4i_hdmi_audio_card;
|
||||
+ struct snd_soc_dai_link_component *comp;
|
||||
+ struct snd_soc_dai_link *link;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = devm_snd_dmaengine_pcm_register(hdmi->dev,
|
||||
+ &sun4i_hdmi_audio_pcm_config, 0);
|
||||
+ if (ret) {
|
||||
+ DRM_ERROR("Could not register PCM\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_snd_soc_register_component(hdmi->dev,
|
||||
+ &sun4i_hdmi_audio_component,
|
||||
+ &sun4i_hdmi_audio_dai, 1);
|
||||
+ if (ret) {
|
||||
+ DRM_ERROR("Could not register DAI\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ link = devm_kzalloc(hdmi->dev, sizeof(*link), GFP_KERNEL);
|
||||
+ if (!link)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ comp = devm_kzalloc(hdmi->dev, sizeof(*comp) * 3, GFP_KERNEL);
|
||||
+ if (!comp)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ link->cpus = &comp[0];
|
||||
+ link->codecs = &comp[1];
|
||||
+ link->platforms = &comp[2];
|
||||
+
|
||||
+ link->num_cpus = 1;
|
||||
+ link->num_codecs = 1;
|
||||
+ link->num_platforms = 1;
|
||||
+
|
||||
+ link->playback_only = 1;
|
||||
+
|
||||
+ link->name = "SUN4I-HDMI";
|
||||
+ link->stream_name = "SUN4I-HDMI PCM";
|
||||
+
|
||||
+ link->codecs->name = dev_name(hdmi->dev);
|
||||
+ link->codecs->dai_name = sun4i_hdmi_audio_dai.name;
|
||||
+
|
||||
+ link->cpus->dai_name = dev_name(hdmi->dev);
|
||||
+
|
||||
+ link->platforms->name = dev_name(hdmi->dev);
|
||||
+
|
||||
+ link->dai_fmt = SND_SOC_DAIFMT_I2S;
|
||||
+
|
||||
+ card->dai_link = link;
|
||||
+ card->num_links = 1;
|
||||
+ card->dev = hdmi->dev;
|
||||
+
|
||||
+ snd_soc_card_set_drvdata(card, hdmi);
|
||||
+ return devm_snd_soc_register_card(hdmi->dev, card);
|
||||
+}
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
|
||||
index a7c4654445c7..79ecd89fb705 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
|
||||
@@ -114,6 +114,9 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder)
|
||||
val |= SUN4I_HDMI_VID_CTRL_HDMI_MODE;
|
||||
|
||||
writel(val, hdmi->base + SUN4I_HDMI_VID_CTRL_REG);
|
||||
+
|
||||
+ if (hdmi->hdmi_audio && sun4i_hdmi_audio_create(hdmi))
|
||||
+ DRM_ERROR("Couldn't create the HDMI audio adapter\n");
|
||||
}
|
||||
|
||||
static void sun4i_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
@@ -218,6 +221,7 @@ static int sun4i_hdmi_get_modes(struct drm_connector *connector)
|
||||
if (!edid)
|
||||
return 0;
|
||||
|
||||
+ hdmi->hdmi_audio = drm_detect_monitor_audio(edid);
|
||||
hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
DRM_DEBUG_DRIVER("Monitor is %s monitor\n",
|
||||
hdmi->hdmi_monitor ? "an HDMI" : "a DVI");
|
@ -331,7 +331,7 @@ CONFIG_ARCH_SUNXI=y
|
||||
# CONFIG_MACH_SUN4I is not set
|
||||
# CONFIG_MACH_SUN5I is not set
|
||||
# CONFIG_MACH_SUN6I is not set
|
||||
CONFIG_MACH_SUN7I=y
|
||||
# CONFIG_MACH_SUN7I is not set
|
||||
CONFIG_MACH_SUN8I=y
|
||||
# CONFIG_MACH_SUN9I is not set
|
||||
CONFIG_ARCH_SUNXI_MC_SMP=y
|
||||
@ -369,7 +369,6 @@ CONFIG_ARM_THUMB=y
|
||||
# CONFIG_ARM_THUMBEE is not set
|
||||
CONFIG_ARM_VIRT_EXT=y
|
||||
CONFIG_SWP_EMULATE=y
|
||||
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||
# CONFIG_CPU_ICACHE_DISABLE is not set
|
||||
# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set
|
||||
# CONFIG_CPU_BPREDICT_DISABLE is not set
|
||||
@ -390,7 +389,6 @@ CONFIG_ARM_L1_CACHE_SHIFT_6=y
|
||||
CONFIG_ARM_L1_CACHE_SHIFT=6
|
||||
CONFIG_ARM_DMA_MEM_BUFFERABLE=y
|
||||
CONFIG_ARM_HEAVY_MB=y
|
||||
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
|
||||
CONFIG_DEBUG_ALIGN_RODATA=y
|
||||
# CONFIG_ARM_ERRATA_430973 is not set
|
||||
CONFIG_ARM_ERRATA_643719=y
|
||||
@ -1213,7 +1211,6 @@ CONFIG_CAN_DEV=y
|
||||
CONFIG_CAN_CALC_BITTIMING=y
|
||||
# CONFIG_CAN_FLEXCAN is not set
|
||||
# CONFIG_CAN_GRCAN is not set
|
||||
# CONFIG_CAN_SUN4I is not set
|
||||
# CONFIG_CAN_TI_HECC is not set
|
||||
# CONFIG_CAN_C_CAN is not set
|
||||
# CONFIG_CAN_CC770 is not set
|
||||
@ -4542,7 +4539,6 @@ CONFIG_RTC_I2C_AND_SPI=y
|
||||
# on-CPU RTC drivers
|
||||
#
|
||||
CONFIG_RTC_DRV_SUN6I=y
|
||||
CONFIG_RTC_DRV_SUNXI=y
|
||||
# CONFIG_RTC_DRV_CADENCE is not set
|
||||
# CONFIG_RTC_DRV_FTRTC010 is not set
|
||||
# CONFIG_RTC_DRV_R7301 is not set
|
||||
@ -4560,7 +4556,6 @@ CONFIG_DMA_ENGINE=y
|
||||
CONFIG_DMA_VIRTUAL_CHANNELS=y
|
||||
CONFIG_DMA_OF=y
|
||||
# CONFIG_ALTERA_MSGDMA is not set
|
||||
CONFIG_DMA_SUN4I=y
|
||||
CONFIG_DMA_SUN6I=y
|
||||
# CONFIG_DW_AXI_DMAC is not set
|
||||
# CONFIG_FSL_EDMA is not set
|
||||
@ -4725,7 +4720,6 @@ CONFIG_CLK_SUNXI_CLOCKS=y
|
||||
# CONFIG_CLK_SUNXI_PRCM_SUN8I is not set
|
||||
# CONFIG_CLK_SUNXI_PRCM_SUN9I is not set
|
||||
CONFIG_SUNXI_CCU=y
|
||||
CONFIG_SUN4I_A10_CCU=y
|
||||
# CONFIG_SUN8I_A23_CCU is not set
|
||||
# CONFIG_SUN8I_A33_CCU is not set
|
||||
# CONFIG_SUN8I_A83T_CCU is not set
|
||||
@ -4743,7 +4737,6 @@ CONFIG_TIMER_OF=y
|
||||
CONFIG_TIMER_PROBE=y
|
||||
CONFIG_CLKSRC_MMIO=y
|
||||
CONFIG_SUN4I_TIMER=y
|
||||
CONFIG_SUN5I_HSTIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER=y
|
||||
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
||||
# CONFIG_MICROCHIP_PIT64B is not set
|
||||
|
Loading…
x
Reference in New Issue
Block a user