Merge pull request #4625 from jernejsk/drop-a20

Allwinner: Remove support for A20
This commit is contained in:
Christian Hewitt 2020-10-25 13:58:50 +04:00 committed by GitHub
commit 9e9b97f2be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 1 additions and 821 deletions

View File

@ -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
}

View File

@ -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"

View File

@ -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);
};
/**

View File

@ -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");

View File

@ -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

View File

@ -21,36 +21,6 @@ import sys
devices = \
{
'Allwinner': {
'A20' : {
'bananapi': {
'dtb': 'sun7i-a20-bananapi.dtb',
'config': 'Bananapi_defconfig'
},
'cubieboard2': {
'dtb': 'sun7i-a20-cubieboard2.dtb',
'config': 'Cubieboard2_defconfig'
},
'cubietruck': {
'dtb': 'sun7i-a20-cubietruck.dtb',
'config': 'Cubietruck_defconfig'
},
'lime': {
'dtb': 'sun7i-a20-olinuxino-lime.dtb',
'config': 'A20-OLinuXino-Lime_defconfig'
},
'lime2': {
'dtb': 'sun7i-a20-olinuxino-lime2.dtb',
'config': 'A20-OLinuXino-Lime2_defconfig'
},
'micro': {
'dtb': 'sun7i-a20-olinuxino-micro.dtb',
'config': 'A20-OLinuXino_MICRO_defconfig'
},
'mk808c': {
'dtb': 'sun7i-a20-mk808c.dtb',
'config': 'MK808C_defconfig'
},
},
'A64': {
'orangepi-win': {
'dtb': 'sun50i-a64-orangepi-win.dtb',