mirror of
https://github.com/home-assistant/operating-system.git
synced 2025-07-28 07:26:28 +00:00
commit
a860374d64
4
.github/release-drafter.yml
vendored
4
.github/release-drafter.yml
vendored
@ -1,4 +0,0 @@
|
||||
template: |
|
||||
## What's Changed
|
||||
|
||||
$CHANGES
|
25
.travis.yml
Normal file
25
.travis.yml
Normal file
@ -0,0 +1,25 @@
|
||||
language: bash
|
||||
|
||||
sudo: required
|
||||
service: docker
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- docker-ce
|
||||
|
||||
before_install:
|
||||
- shopt -s globstar
|
||||
- docker pull koalaman/shellcheck
|
||||
|
||||
script:
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck scripts/*.sh
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck buildroot-external/scripts/*.sh
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck buildroot-external/scripts/*.sh
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck buildroot-external/board/**/*.sh
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck buildroot-external/rootfs-overlay/usr/sbin/*
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck buildroot-external/rootfs-overlay/usr/libexec/*
|
||||
- docker run -v $(pwd):/mnt koalaman/shellcheck buildroot-external/rootfs-overlay/usr/lib/rauc/*
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
@ -42,6 +42,16 @@ The udev rules folder `/etc/udev/rules.d` is persistent and you can add your con
|
||||
|
||||
You can manual add, edit or remove connections configurations from `/etc/NetworkManager/system-connections`.
|
||||
|
||||
### NTP
|
||||
|
||||
You can manual edit the systemd timesync file on `/etc/systemd/timesyncd.conf`.
|
||||
Our default ntp configuration look like:
|
||||
```
|
||||
[Time]
|
||||
NTP=time1.google.com time2.google.com time3.google.com
|
||||
FallbackNTP=0.pool.ntp.org 1.pool.ntp.org 2.pool.ntp.org 3.pool.ntp.org
|
||||
```
|
||||
|
||||
[systemd-modules]: https://www.freedesktop.org/software/systemd/man/modules-load.d.html
|
||||
[network.md]: network.md
|
||||
[hassos-release]: https://github.com/home-assistant/hassos/releases/
|
||||
|
@ -6,4 +6,4 @@
|
||||
| Open Virtual Applicance | 4.14.82 |
|
||||
| Raspberry Pi | 4.14.81 |
|
||||
| Tinker Board | 4.14.82 |
|
||||
| Odroid-C2 | 4.14.67 |
|
||||
| Odroid-C2 | 4.18.20 |
|
||||
|
@ -1,28 +1,28 @@
|
||||
#!/bin/bash
|
||||
# shellcheck disable=SC2155
|
||||
|
||||
function hassos_pre_image() {
|
||||
local BOOT_DATA="$(path_boot_dir)"
|
||||
local SPL_IMG="$(path_spl_img)"
|
||||
|
||||
cp -t ${BOOT_DATA} \
|
||||
${BINARIES_DIR}/boot.scr \
|
||||
${BINARIES_DIR}/rk3288-tinker.dtb
|
||||
cp -t "${BOOT_DATA}" \
|
||||
"${BINARIES_DIR}/boot.scr" \
|
||||
"${BINARIES_DIR}/rk3288-tinker.dtb"
|
||||
|
||||
echo "console=tty1" > ${BOOT_DATA}/cmdline.txt
|
||||
echo "console=tty1" > "${BOOT_DATA}/cmdline.txt"
|
||||
|
||||
# Create boot binary
|
||||
rm -f ${BINARIES_DIR}/u-boot-spl-dtb.img
|
||||
mkimage -n rk3288 -T rksd -d ${BINARIES_DIR}/u-boot-spl-dtb.bin ${BINARIES_DIR}/u-boot-spl-dtb.img
|
||||
cat ${BINARIES_DIR}/u-boot-dtb.bin >> ${BINARIES_DIR}/u-boot-spl-dtb.img
|
||||
rm -f "${BINARIES_DIR}/u-boot-spl-dtb.img"
|
||||
mkimage -n rk3288 -T rksd -d "${BINARIES_DIR}/u-boot-spl-dtb.bin" "${BINARIES_DIR}/u-boot-spl-dtb.img"
|
||||
cat "${BINARIES_DIR}/u-boot-dtb.bin" >> "${BINARIES_DIR}/u-boot-spl-dtb.img"
|
||||
|
||||
# SPL
|
||||
create_spl_image
|
||||
|
||||
dd if=${BINARIES_DIR}/u-boot-spl-dtb.img of=${SPL_IMG} conv=notrunc bs=512 seek=64
|
||||
dd if="${BINARIES_DIR}/u-boot-spl-dtb.img" of="${SPL_IMG}" conv=notrunc bs=512 seek=64
|
||||
}
|
||||
|
||||
|
||||
function hassos_post_image() {
|
||||
convert_disk_image_gz
|
||||
}
|
||||
|
||||
|
5
buildroot-external/board/asus/tinker/patches/README.md
Normal file
5
buildroot-external/board/asus/tinker/patches/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
## Kernel
|
||||
https://github.com/armbian/build/tree/master/patch/kernel/rockchip-next
|
||||
|
||||
## u-boot
|
||||
https://github.com/armbian/build/tree/master/patch/u-boot/u-boot-rockchip/board_tinkerboard
|
@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
# shellcheck disable=SC2155
|
||||
|
||||
function hassos_pre_image() {
|
||||
local BOOT_DATA="$(path_boot_dir)"
|
||||
@ -6,18 +7,18 @@ function hassos_pre_image() {
|
||||
local UBOOT_GXBB="${BINARIES_DIR}/u-boot.gxbb"
|
||||
local spl_img="$(path_spl_img)"
|
||||
|
||||
cp ${BINARIES_DIR}/boot.scr ${BOOT_DATA}/boot.scr
|
||||
cp ${BOARD_DIR}/boot-env.txt ${BOOT_DATA}/config.txt
|
||||
cp ${BINARIES_DIR}/meson-gxbb-odroidc2.dtb ${BOOT_DATA}/meson-gxbb-odroidc2.dtb
|
||||
cp "${BINARIES_DIR}/boot.scr" "${BOOT_DATA}/boot.scr"
|
||||
cp "${BOARD_DIR}/boot-env.txt" "${BOOT_DATA}/config.txt"
|
||||
cp "${BINARIES_DIR}/meson-gxbb-odroidc2.dtb" "${BOOT_DATA}/meson-gxbb-odroidc2.dtb"
|
||||
|
||||
echo "console=tty0 console=ttyAML0,115200n8" > ${BOOT_DATA}/cmdline.txt
|
||||
echo "console=tty0 console=ttyAML0,115200n8" > "${BOOT_DATA}/cmdline.txt"
|
||||
|
||||
# SPL
|
||||
create_spl_image
|
||||
|
||||
dd if=${BL1} of=${spl_img} conv=notrunc bs=1 count=440
|
||||
dd if=${BL1} of=${spl_img} conv=notrunc bs=512 skip=1 seek=1
|
||||
dd if=${UBOOT_GXBB} of=${spl_img} conv=notrunc bs=512 seek=97
|
||||
dd if="${BL1}" of="${spl_img}" conv=notrunc bs=1 count=440
|
||||
dd if="${BL1}" of="${spl_img}" conv=notrunc bs=512 skip=1 seek=1
|
||||
dd if="${UBOOT_GXBB}" of="${spl_img}" conv=notrunc bs=512 seek=97
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
kernel patches from
|
||||
https://github.com/superna9999/meta-meson/tree/sumo/recipes-kernel/linux/linux-yocto-meson64-4.14
|
||||
kernel patches from scpcom
|
||||
https://forum.odroid.com/viewtopic.php?f=135&t=22717&start=900#p233963
|
||||
|
@ -0,0 +1,13 @@
|
||||
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
|
||||
index f839ecd9..cd276162 100644
|
||||
--- a/arch/arm64/Makefile
|
||||
+++ b/arch/arm64/Makefile
|
||||
@@ -103,7 +103,7 @@ core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
|
||||
# Default target when executing plain make
|
||||
boot := arch/arm64/boot
|
||||
-KBUILD_IMAGE := $(boot)/Image.gz
|
||||
+KBUILD_IMAGE := $(boot)/Image
|
||||
KBUILD_DTBS := dtbs
|
||||
|
||||
all: Image.gz $(KBUILD_DTBS)
|
@ -0,0 +1,49 @@
|
||||
From 4796e434b5785e3d9f95e988363c407b1e09bb91 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
Date: Sat, 28 Jul 2018 22:40:27 +0200
|
||||
Subject: [PATCH] dt-bindings: soc: amlogic: add meson-canvas documentation
|
||||
|
||||
DT bindings doc for amlogic,meson-canvas
|
||||
|
||||
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
.../bindings/soc/amlogic/amlogic,canvas.txt | 29 +++++++++++++++++++
|
||||
1 file changed, 29 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt b/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt
|
||||
new file mode 100644
|
||||
index 0000000000000..436d2106e80da
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/soc/amlogic/amlogic,canvas.txt
|
||||
@@ -0,0 +1,29 @@
|
||||
+Amlogic Canvas
|
||||
+================================
|
||||
+
|
||||
+A canvas is a collection of metadata that describes a pixel buffer.
|
||||
+Those metadata include: width, height, phyaddr, wrapping, block mode
|
||||
+and endianness.
|
||||
+
|
||||
+Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data
|
||||
+rather than use the phy addresses directly. For instance, this is the case for
|
||||
+the video decoders and the display.
|
||||
+
|
||||
+Amlogic SoCs have 256 canvas.
|
||||
+
|
||||
+Device Tree Bindings:
|
||||
+---------------------
|
||||
+
|
||||
+Video Lookup Table
|
||||
+--------------------------
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: "amlogic,canvas"
|
||||
+- reg: Base physical address and size of the canvas registers.
|
||||
+
|
||||
+Example:
|
||||
+
|
||||
+canvas: video-lut@48 {
|
||||
+ compatible = "amlogic,canvas";
|
||||
+ reg = <0x0 0x48 0x0 0x14>;
|
||||
+};
|
@ -0,0 +1,313 @@
|
||||
From 21c3e7d31208b0c4fb4a6c0a8c52e6820a40596a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
Date: Fri, 20 Apr 2018 13:17:07 +0200
|
||||
Subject: [PATCH] soc: amlogic: add meson-canvas driver
|
||||
|
||||
Amlogic SoCs have a repository of 256 canvas which they use to
|
||||
describe pixel buffers.
|
||||
|
||||
They contain metadata like width, height, block mode, endianness [..]
|
||||
|
||||
Many IPs within those SoCs like vdec/vpu rely on those canvas to read/write
|
||||
pixels.
|
||||
|
||||
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
drivers/soc/amlogic/Kconfig | 7 +
|
||||
drivers/soc/amlogic/Makefile | 1 +
|
||||
drivers/soc/amlogic/meson-canvas.c | 185 +++++++++++++++++++++++
|
||||
include/linux/soc/amlogic/meson-canvas.h | 65 ++++++++
|
||||
4 files changed, 258 insertions(+)
|
||||
create mode 100644 drivers/soc/amlogic/meson-canvas.c
|
||||
create mode 100644 include/linux/soc/amlogic/meson-canvas.h
|
||||
|
||||
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
|
||||
index b04f6e4aedbc1..2f282b4729120 100644
|
||||
--- a/drivers/soc/amlogic/Kconfig
|
||||
+++ b/drivers/soc/amlogic/Kconfig
|
||||
@@ -1,5 +1,12 @@
|
||||
menu "Amlogic SoC drivers"
|
||||
|
||||
+config MESON_CANVAS
|
||||
+ tristate "Amlogic Meson Canvas driver"
|
||||
+ depends on ARCH_MESON || COMPILE_TEST
|
||||
+ default n
|
||||
+ help
|
||||
+ Say yes to support the canvas IP for Amlogic SoCs.
|
||||
+
|
||||
config MESON_GX_SOCINFO
|
||||
bool "Amlogic Meson GX SoC Information driver"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
|
||||
index 8fa321893928d..0ab16d35ac36d 100644
|
||||
--- a/drivers/soc/amlogic/Makefile
|
||||
+++ b/drivers/soc/amlogic/Makefile
|
||||
@@ -1,3 +1,4 @@
|
||||
+obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
|
||||
obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
|
||||
obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
|
||||
obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
|
||||
diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c
|
||||
new file mode 100644
|
||||
index 0000000000000..fce33ca76bb62
|
||||
--- /dev/null
|
||||
+++ b/drivers/soc/amlogic/meson-canvas.c
|
||||
@@ -0,0 +1,185 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2018 BayLibre, SAS
|
||||
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
||||
+ * Copyright (C) 2014 Endless Mobile
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/soc/amlogic/meson-canvas.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/io.h>
|
||||
+
|
||||
+#define NUM_CANVAS 256
|
||||
+
|
||||
+/* DMC Registers */
|
||||
+#define DMC_CAV_LUT_DATAL 0x00
|
||||
+ #define CANVAS_WIDTH_LBIT 29
|
||||
+ #define CANVAS_WIDTH_LWID 3
|
||||
+#define DMC_CAV_LUT_DATAH 0x04
|
||||
+ #define CANVAS_WIDTH_HBIT 0
|
||||
+ #define CANVAS_HEIGHT_BIT 9
|
||||
+ #define CANVAS_WRAP_BIT 22
|
||||
+ #define CANVAS_BLKMODE_BIT 24
|
||||
+ #define CANVAS_ENDIAN_BIT 26
|
||||
+#define DMC_CAV_LUT_ADDR 0x08
|
||||
+ #define CANVAS_LUT_WR_EN BIT(9)
|
||||
+ #define CANVAS_LUT_RD_EN BIT(8)
|
||||
+
|
||||
+struct meson_canvas {
|
||||
+ struct device *dev;
|
||||
+ void __iomem *reg_base;
|
||||
+ spinlock_t lock; /* canvas device lock */
|
||||
+ u8 used[NUM_CANVAS];
|
||||
+};
|
||||
+
|
||||
+static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
|
||||
+{
|
||||
+ writel_relaxed(val, canvas->reg_base + reg);
|
||||
+}
|
||||
+
|
||||
+static u32 canvas_read(struct meson_canvas *canvas, u32 reg)
|
||||
+{
|
||||
+ return readl_relaxed(canvas->reg_base + reg);
|
||||
+}
|
||||
+
|
||||
+struct meson_canvas *meson_canvas_get(struct device *dev)
|
||||
+{
|
||||
+ struct device_node *canvas_node;
|
||||
+ struct platform_device *canvas_pdev;
|
||||
+
|
||||
+ canvas_node = of_parse_phandle(dev->of_node, "amlogic,canvas", 0);
|
||||
+ if (!canvas_node)
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+
|
||||
+ canvas_pdev = of_find_device_by_node(canvas_node);
|
||||
+ if (!canvas_pdev)
|
||||
+ return ERR_PTR(-EPROBE_DEFER);
|
||||
+
|
||||
+ return dev_get_drvdata(&canvas_pdev->dev);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_canvas_get);
|
||||
+
|
||||
+int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
|
||||
+ u32 addr, u32 stride, u32 height,
|
||||
+ unsigned int wrap,
|
||||
+ unsigned int blkmode,
|
||||
+ unsigned int endian)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&canvas->lock, flags);
|
||||
+ if (!canvas->used[canvas_index]) {
|
||||
+ dev_err(canvas->dev,
|
||||
+ "Trying to setup non allocated canvas %u\n",
|
||||
+ canvas_index);
|
||||
+ spin_unlock_irqrestore(&canvas->lock, flags);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ canvas_write(canvas, DMC_CAV_LUT_DATAL,
|
||||
+ ((addr + 7) >> 3) |
|
||||
+ (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
|
||||
+
|
||||
+ canvas_write(canvas, DMC_CAV_LUT_DATAH,
|
||||
+ ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
|
||||
+ CANVAS_WIDTH_HBIT) |
|
||||
+ (height << CANVAS_HEIGHT_BIT) |
|
||||
+ (wrap << CANVAS_WRAP_BIT) |
|
||||
+ (blkmode << CANVAS_BLKMODE_BIT) |
|
||||
+ (endian << CANVAS_ENDIAN_BIT));
|
||||
+
|
||||
+ canvas_write(canvas, DMC_CAV_LUT_ADDR,
|
||||
+ CANVAS_LUT_WR_EN | canvas_index);
|
||||
+
|
||||
+ /* Force a read-back to make sure everything is flushed. */
|
||||
+ canvas_read(canvas, DMC_CAV_LUT_DATAH);
|
||||
+ spin_unlock_irqrestore(&canvas->lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_canvas_config);
|
||||
+
|
||||
+int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index)
|
||||
+{
|
||||
+ int i;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&canvas->lock, flags);
|
||||
+ for (i = 0; i < NUM_CANVAS; ++i) {
|
||||
+ if (!canvas->used[i]) {
|
||||
+ canvas->used[i] = 1;
|
||||
+ spin_unlock_irqrestore(&canvas->lock, flags);
|
||||
+ *canvas_index = i;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ spin_unlock_irqrestore(&canvas->lock, flags);
|
||||
+
|
||||
+ dev_err(canvas->dev, "No more canvas available\n");
|
||||
+ return -ENODEV;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_canvas_alloc);
|
||||
+
|
||||
+int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&canvas->lock, flags);
|
||||
+ if (!canvas->used[canvas_index]) {
|
||||
+ dev_err(canvas->dev,
|
||||
+ "Trying to free unused canvas %u\n", canvas_index);
|
||||
+ spin_unlock_irqrestore(&canvas->lock, flags);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ canvas->used[canvas_index] = 0;
|
||||
+ spin_unlock_irqrestore(&canvas->lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_canvas_free);
|
||||
+
|
||||
+static int meson_canvas_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct resource *res;
|
||||
+ struct meson_canvas *canvas;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+
|
||||
+ canvas = devm_kzalloc(dev, sizeof(*canvas), GFP_KERNEL);
|
||||
+ if (!canvas)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ canvas->reg_base = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(canvas->reg_base))
|
||||
+ return PTR_ERR(canvas->reg_base);
|
||||
+
|
||||
+ canvas->dev = dev;
|
||||
+ spin_lock_init(&canvas->lock);
|
||||
+ dev_set_drvdata(dev, canvas);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id canvas_dt_match[] = {
|
||||
+ { .compatible = "amlogic,canvas" },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, canvas_dt_match);
|
||||
+
|
||||
+static struct platform_driver meson_canvas_driver = {
|
||||
+ .probe = meson_canvas_probe,
|
||||
+ .driver = {
|
||||
+ .name = "amlogic-canvas",
|
||||
+ .of_match_table = canvas_dt_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_canvas_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Amlogic Canvas driver");
|
||||
+MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/include/linux/soc/amlogic/meson-canvas.h b/include/linux/soc/amlogic/meson-canvas.h
|
||||
new file mode 100644
|
||||
index 0000000000000..b4dde2fbeb3fb
|
||||
--- /dev/null
|
||||
+++ b/include/linux/soc/amlogic/meson-canvas.h
|
||||
@@ -0,0 +1,65 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2018 BayLibre, SAS
|
||||
+ */
|
||||
+#ifndef __SOC_MESON_CANVAS_H
|
||||
+#define __SOC_MESON_CANVAS_H
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+
|
||||
+#define MESON_CANVAS_WRAP_NONE 0x00
|
||||
+#define MESON_CANVAS_WRAP_X 0x01
|
||||
+#define MESON_CANVAS_WRAP_Y 0x02
|
||||
+
|
||||
+#define MESON_CANVAS_BLKMODE_LINEAR 0x00
|
||||
+#define MESON_CANVAS_BLKMODE_32x32 0x01
|
||||
+#define MESON_CANVAS_BLKMODE_64x64 0x02
|
||||
+
|
||||
+#define MESON_CANVAS_ENDIAN_SWAP16 0x1
|
||||
+#define MESON_CANVAS_ENDIAN_SWAP32 0x3
|
||||
+#define MESON_CANVAS_ENDIAN_SWAP64 0x7
|
||||
+#define MESON_CANVAS_ENDIAN_SWAP128 0xf
|
||||
+
|
||||
+struct meson_canvas;
|
||||
+
|
||||
+/**
|
||||
+ * meson_canvas_get() - get a canvas provider instance
|
||||
+ *
|
||||
+ * @dev: consumer device pointer
|
||||
+ */
|
||||
+struct meson_canvas *meson_canvas_get(struct device *dev);
|
||||
+
|
||||
+/**
|
||||
+ * meson_canvas_alloc() - take ownership of a canvas
|
||||
+ *
|
||||
+ * @canvas: canvas provider instance retrieved from meson_canvas_get()
|
||||
+ * @canvas_index: will be filled with the canvas ID
|
||||
+ */
|
||||
+int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index);
|
||||
+
|
||||
+/**
|
||||
+ * meson_canvas_free() - remove ownership from a canvas
|
||||
+ *
|
||||
+ * @canvas: canvas provider instance retrieved from meson_canvas_get()
|
||||
+ * @canvas_index: canvas ID that was obtained via meson_canvas_alloc()
|
||||
+ */
|
||||
+int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index);
|
||||
+
|
||||
+/**
|
||||
+ * meson_canvas_config() - configure a canvas
|
||||
+ *
|
||||
+ * @canvas: canvas provider instance retrieved from meson_canvas_get()
|
||||
+ * @canvas_index: canvas ID that was obtained via meson_canvas_alloc()
|
||||
+ * @addr: physical address to the pixel buffer
|
||||
+ * @stride: width of the buffer
|
||||
+ * @height: height of the buffer
|
||||
+ * @wrap: undocumented
|
||||
+ * @blkmode: block mode (linear, 32x32, 64x64)
|
||||
+ * @endian: byte swapping (swap16, swap32, swap64, swap128)
|
||||
+ */
|
||||
+int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
|
||||
+ u32 addr, u32 stride, u32 height,
|
||||
+ unsigned int wrap, unsigned int blkmode,
|
||||
+ unsigned int endian);
|
||||
+
|
||||
+#endif
|
@ -0,0 +1,38 @@
|
||||
From e4c19f493a541cd00df42c02ec8f544f9835cbe5 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
Date: Fri, 20 Apr 2018 16:09:09 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson-gx: add dmcbus and canvas nodes.
|
||||
|
||||
DMC is a small memory region with various registers,
|
||||
including the ones needed for the canvas module.
|
||||
|
||||
Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
index b8dc4dbb391b6..5dd63ecf8b05b 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -423,6 +423,19 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ dmcbus: bus@c8838000 {
|
||||
+ compatible = "simple-bus";
|
||||
+ reg = <0x0 0xc8838000 0x0 0x400>;
|
||||
+ #address-cells = <2>;
|
||||
+ #size-cells = <2>;
|
||||
+ ranges = <0x0 0x0 0x0 0xc8838000 0x0 0x400>;
|
||||
+
|
||||
+ canvas: video-lut@48 {
|
||||
+ compatible = "amlogic,canvas";
|
||||
+ reg = <0x0 0x48 0x0 0x14>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
hiubus: bus@c883c000 {
|
||||
compatible = "simple-bus";
|
||||
reg = <0x0 0xc883c000 0x0 0x2000>;
|
@ -0,0 +1,366 @@
|
||||
From 665dbad80386dcb9ac78ec6153d8d518da9bb50e Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
Date: Fri, 20 Apr 2018 16:22:17 +0200
|
||||
Subject: [PATCH] drm/meson: convert to the new canvas module
|
||||
|
||||
This removes the meson_canvas files within the meson/drm layer
|
||||
and makes use of the new canvas module that is referenced in the dts.
|
||||
|
||||
Canvases can be used by different IPs and modules, and it is as such
|
||||
preferable to rely on a module that can safely dispatch canvases on
|
||||
demand.
|
||||
|
||||
Signed-off-by: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
---
|
||||
.../bindings/display/amlogic,meson-vpu.txt | 9 +--
|
||||
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 7 +-
|
||||
drivers/gpu/drm/meson/Kconfig | 1 +
|
||||
drivers/gpu/drm/meson/Makefile | 2 +-
|
||||
drivers/gpu/drm/meson/meson_canvas.c | 70 -------------------
|
||||
drivers/gpu/drm/meson/meson_canvas.h | 42 -----------
|
||||
drivers/gpu/drm/meson/meson_crtc.c | 9 ++-
|
||||
drivers/gpu/drm/meson/meson_drv.c | 22 ++----
|
||||
drivers/gpu/drm/meson/meson_drv.h | 5 +-
|
||||
drivers/gpu/drm/meson/meson_plane.c | 3 +-
|
||||
drivers/gpu/drm/meson/meson_viu.c | 1 -
|
||||
11 files changed, 26 insertions(+), 145 deletions(-)
|
||||
delete mode 100644 drivers/gpu/drm/meson/meson_canvas.c
|
||||
delete mode 100644 drivers/gpu/drm/meson/meson_canvas.h
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
|
||||
index 057b81335775e..60b6e13986365 100644
|
||||
--- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
|
||||
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
|
||||
@@ -60,9 +60,9 @@ Required properties:
|
||||
- reg: base address and size of he following memory-mapped regions :
|
||||
- vpu
|
||||
- hhi
|
||||
- - dmc
|
||||
- reg-names: should contain the names of the previous memory regions
|
||||
- interrupts: should contain the VENC Vsync interrupt number
|
||||
+- amlogic,canvas: should point to a meson canvas provider node
|
||||
|
||||
Optional properties:
|
||||
- power-domains: Optional phandle to associated power domain as described in
|
||||
@@ -98,13 +98,14 @@ tv-connector {
|
||||
vpu: vpu@d0100000 {
|
||||
compatible = "amlogic,meson-gxbb-vpu";
|
||||
reg = <0x0 0xd0100000 0x0 0x100000>,
|
||||
- <0x0 0xc883c000 0x0 0x1000>,
|
||||
- <0x0 0xc8838000 0x0 0x1000>;
|
||||
- reg-names = "vpu", "hhi", "dmc";
|
||||
+ <0x0 0xc883c000 0x0 0x1000>;
|
||||
+ reg-names = "vpu", "hhi";
|
||||
interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
+ amlogic,canvas = <&canvas>;
|
||||
+
|
||||
/* CVBS VDAC output port */
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
index 5dd63ecf8b05b..737b741df0355 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -499,13 +499,14 @@
|
||||
vpu: vpu@d0100000 {
|
||||
compatible = "amlogic,meson-gx-vpu";
|
||||
reg = <0x0 0xd0100000 0x0 0x100000>,
|
||||
- <0x0 0xc883c000 0x0 0x1000>,
|
||||
- <0x0 0xc8838000 0x0 0x1000>;
|
||||
- reg-names = "vpu", "hhi", "dmc";
|
||||
+ <0x0 0xc883c000 0x0 0x1000>;
|
||||
+ reg-names = "vpu", "hhi";
|
||||
interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
+ amlogic,canvas = <&canvas>;
|
||||
+
|
||||
/* CVBS VDAC output port */
|
||||
cvbs_vdac_port: port@0 {
|
||||
reg = <0>;
|
||||
diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
|
||||
index 3ce51d8dfe1c8..c28b69f485555 100644
|
||||
--- a/drivers/gpu/drm/meson/Kconfig
|
||||
+++ b/drivers/gpu/drm/meson/Kconfig
|
||||
@@ -7,6 +7,7 @@ config DRM_MESON
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select VIDEOMODE_HELPERS
|
||||
select REGMAP_MMIO
|
||||
+ select MESON_CANVAS
|
||||
|
||||
config DRM_MESON_DW_HDMI
|
||||
tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
|
||||
diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
|
||||
index c5c4cc362f024..bd67429185ff7 100644
|
||||
--- a/drivers/gpu/drm/meson/Makefile
|
||||
+++ b/drivers/gpu/drm/meson/Makefile
|
||||
@@ -1,5 +1,5 @@
|
||||
meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
|
||||
-meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
|
||||
+meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o
|
||||
|
||||
obj-$(CONFIG_DRM_MESON) += meson-drm.o
|
||||
obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
|
||||
diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c
|
||||
deleted file mode 100644
|
||||
index 08f6073d967e0..0000000000000
|
||||
--- a/drivers/gpu/drm/meson/meson_canvas.c
|
||||
+++ /dev/null
|
||||
@@ -1,70 +0,0 @@
|
||||
-/*
|
||||
- * Copyright (C) 2016 BayLibre, SAS
|
||||
- * Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
- * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
|
||||
- * Copyright (C) 2014 Endless Mobile
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or
|
||||
- * modify it under the terms of the GNU General Public License as
|
||||
- * published by the Free Software Foundation; either version 2 of the
|
||||
- * License, or (at your option) any later version.
|
||||
- *
|
||||
- * This program is distributed in the hope that it will be useful, but
|
||||
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
- * General Public License for more details.
|
||||
- *
|
||||
- * You should have received a copy of the GNU General Public License
|
||||
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
- */
|
||||
-
|
||||
-#include <linux/kernel.h>
|
||||
-#include <linux/module.h>
|
||||
-#include "meson_drv.h"
|
||||
-#include "meson_canvas.h"
|
||||
-#include "meson_registers.h"
|
||||
-
|
||||
-/**
|
||||
- * DOC: Canvas
|
||||
- *
|
||||
- * CANVAS is a memory zone where physical memory frames information
|
||||
- * are stored for the VIU to scanout.
|
||||
- */
|
||||
-
|
||||
-/* DMC Registers */
|
||||
-#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */
|
||||
-#define CANVAS_WIDTH_LBIT 29
|
||||
-#define CANVAS_WIDTH_LWID 3
|
||||
-#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */
|
||||
-#define CANVAS_WIDTH_HBIT 0
|
||||
-#define CANVAS_HEIGHT_BIT 9
|
||||
-#define CANVAS_BLKMODE_BIT 24
|
||||
-#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
|
||||
-#define CANVAS_LUT_WR_EN (0x2 << 8)
|
||||
-#define CANVAS_LUT_RD_EN (0x1 << 8)
|
||||
-
|
||||
-void meson_canvas_setup(struct meson_drm *priv,
|
||||
- uint32_t canvas_index, uint32_t addr,
|
||||
- uint32_t stride, uint32_t height,
|
||||
- unsigned int wrap,
|
||||
- unsigned int blkmode)
|
||||
-{
|
||||
- unsigned int val;
|
||||
-
|
||||
- regmap_write(priv->dmc, DMC_CAV_LUT_DATAL,
|
||||
- (((addr + 7) >> 3)) |
|
||||
- (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
|
||||
-
|
||||
- regmap_write(priv->dmc, DMC_CAV_LUT_DATAH,
|
||||
- ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
|
||||
- CANVAS_WIDTH_HBIT) |
|
||||
- (height << CANVAS_HEIGHT_BIT) |
|
||||
- (wrap << 22) |
|
||||
- (blkmode << CANVAS_BLKMODE_BIT));
|
||||
-
|
||||
- regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
|
||||
- CANVAS_LUT_WR_EN | canvas_index);
|
||||
-
|
||||
- /* Force a read-back to make sure everything is flushed. */
|
||||
- regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val);
|
||||
-}
|
||||
diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h
|
||||
deleted file mode 100644
|
||||
index af1759da4b275..0000000000000
|
||||
--- a/drivers/gpu/drm/meson/meson_canvas.h
|
||||
+++ /dev/null
|
||||
@@ -1,42 +0,0 @@
|
||||
-/*
|
||||
- * Copyright (C) 2016 BayLibre, SAS
|
||||
- * Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
- * Copyright (C) 2014 Endless Mobile
|
||||
- *
|
||||
- * This program is free software; you can redistribute it and/or
|
||||
- * modify it under the terms of the GNU General Public License as
|
||||
- * published by the Free Software Foundation; either version 2 of the
|
||||
- * License, or (at your option) any later version.
|
||||
- *
|
||||
- * This program is distributed in the hope that it will be useful, but
|
||||
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
- * General Public License for more details.
|
||||
- *
|
||||
- * You should have received a copy of the GNU General Public License
|
||||
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
- */
|
||||
-
|
||||
-/* Canvas LUT Memory */
|
||||
-
|
||||
-#ifndef __MESON_CANVAS_H
|
||||
-#define __MESON_CANVAS_H
|
||||
-
|
||||
-#define MESON_CANVAS_ID_OSD1 0x4e
|
||||
-
|
||||
-/* Canvas configuration. */
|
||||
-#define MESON_CANVAS_WRAP_NONE 0x00
|
||||
-#define MESON_CANVAS_WRAP_X 0x01
|
||||
-#define MESON_CANVAS_WRAP_Y 0x02
|
||||
-
|
||||
-#define MESON_CANVAS_BLKMODE_LINEAR 0x00
|
||||
-#define MESON_CANVAS_BLKMODE_32x32 0x01
|
||||
-#define MESON_CANVAS_BLKMODE_64x64 0x02
|
||||
-
|
||||
-void meson_canvas_setup(struct meson_drm *priv,
|
||||
- uint32_t canvas_index, uint32_t addr,
|
||||
- uint32_t stride, uint32_t height,
|
||||
- unsigned int wrap,
|
||||
- unsigned int blkmode);
|
||||
-
|
||||
-#endif /* __MESON_CANVAS_H */
|
||||
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
index 05520202c9677..1ca9c6c45f9b9 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "meson_venc.h"
|
||||
#include "meson_vpp.h"
|
||||
#include "meson_viu.h"
|
||||
-#include "meson_canvas.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
/* CRTC definition */
|
||||
@@ -193,10 +192,10 @@ void meson_crtc_irq(struct meson_drm *priv)
|
||||
} else
|
||||
meson_vpp_disable_interlace_vscaler_osd1(priv);
|
||||
|
||||
- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
|
||||
- priv->viu.osd1_addr, priv->viu.osd1_stride,
|
||||
- priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
|
||||
- MESON_CANVAS_BLKMODE_LINEAR);
|
||||
+ meson_canvas_config(priv->canvas, priv->canvas_id_osd1,
|
||||
+ priv->viu.osd1_addr, priv->viu.osd1_stride,
|
||||
+ priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
|
||||
+ MESON_CANVAS_BLKMODE_LINEAR, 0);
|
||||
|
||||
/* Enable OSD1 */
|
||||
writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
|
||||
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
|
||||
index d3443125e6616..fb5b0e3c5efce 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_drv.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_drv.c
|
||||
@@ -47,7 +47,6 @@
|
||||
#include "meson_vpp.h"
|
||||
#include "meson_viu.h"
|
||||
#include "meson_venc.h"
|
||||
-#include "meson_canvas.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
#define DRIVER_NAME "meson"
|
||||
@@ -216,25 +215,15 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
|
||||
goto free_drm;
|
||||
}
|
||||
|
||||
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
|
||||
- if (!res) {
|
||||
- ret = -EINVAL;
|
||||
- goto free_drm;
|
||||
- }
|
||||
- /* Simply ioremap since it may be a shared register zone */
|
||||
- regs = devm_ioremap(dev, res->start, resource_size(res));
|
||||
- if (!regs) {
|
||||
- ret = -EADDRNOTAVAIL;
|
||||
+ priv->canvas = meson_canvas_get(dev);
|
||||
+ if (IS_ERR(priv->canvas)) {
|
||||
+ ret = PTR_ERR(priv->canvas);
|
||||
goto free_drm;
|
||||
}
|
||||
|
||||
- priv->dmc = devm_regmap_init_mmio(dev, regs,
|
||||
- &meson_regmap_config);
|
||||
- if (IS_ERR(priv->dmc)) {
|
||||
- dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
|
||||
- ret = PTR_ERR(priv->dmc);
|
||||
+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
|
||||
+ if (ret)
|
||||
goto free_drm;
|
||||
- }
|
||||
|
||||
priv->vsync_irq = platform_get_irq(pdev, 0);
|
||||
|
||||
@@ -315,6 +304,7 @@ static void meson_drv_unbind(struct device *dev)
|
||||
struct drm_device *drm = dev_get_drvdata(dev);
|
||||
struct meson_drm *priv = drm->dev_private;
|
||||
|
||||
+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
|
||||
drm_dev_unregister(drm);
|
||||
drm_kms_helper_poll_fini(drm);
|
||||
drm_fbdev_cma_fini(priv->fbdev);
|
||||
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
|
||||
index 8450d6ac8c9bc..9e902a6df7843 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_drv.h
|
||||
+++ b/drivers/gpu/drm/meson/meson_drv.h
|
||||
@@ -22,15 +22,18 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
+#include <linux/soc/amlogic/meson-canvas.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
struct meson_drm {
|
||||
struct device *dev;
|
||||
void __iomem *io_base;
|
||||
struct regmap *hhi;
|
||||
- struct regmap *dmc;
|
||||
int vsync_irq;
|
||||
|
||||
+ struct meson_canvas *canvas;
|
||||
+ u8 canvas_id_osd1;
|
||||
+
|
||||
struct drm_device *drm;
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_fbdev_cma *fbdev;
|
||||
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
|
||||
index 12c80dfcff59b..8745f9209625b 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_plane.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_plane.c
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "meson_plane.h"
|
||||
#include "meson_vpp.h"
|
||||
#include "meson_viu.h"
|
||||
-#include "meson_canvas.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
struct meson_plane {
|
||||
@@ -105,7 +104,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
|
||||
OSD_BLK0_ENABLE;
|
||||
|
||||
/* Set up BLK0 to point to the right canvas */
|
||||
- priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
|
||||
+ priv->viu.osd1_blk0_cfg[0] = ((priv->canvas_id_osd1 << OSD_CANVAS_SEL) |
|
||||
OSD_ENDIANNESS_LE);
|
||||
|
||||
/* On GXBB, Use the old non-HDR RGB2YUV converter */
|
||||
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
|
||||
index 6bcfa527c1801..5b48c4c0985b5 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_viu.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_viu.c
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "meson_viu.h"
|
||||
#include "meson_vpp.h"
|
||||
#include "meson_venc.h"
|
||||
-#include "meson_canvas.h"
|
||||
#include "meson_registers.h"
|
||||
|
||||
/**
|
@ -0,0 +1,82 @@
|
||||
From 0ceff9fb866173338b3ca79657ce6bf9aa3b2a9a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:05:05 +0200
|
||||
Subject: [PATCH] dt-bindings: media: add Amlogic Video Decoder Bindings
|
||||
|
||||
Add documentation for the meson vdec dts node.
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
.../bindings/media/amlogic,vdec.txt | 63 +++++++++++++++++++
|
||||
1 file changed, 63 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/media/amlogic,vdec.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/media/amlogic,vdec.txt b/Documentation/devicetree/bindings/media/amlogic,vdec.txt
|
||||
new file mode 100644
|
||||
index 0000000000000..c6450f2e7f28f
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/media/amlogic,vdec.txt
|
||||
@@ -0,0 +1,63 @@
|
||||
+Amlogic Video Decoder
|
||||
+================================
|
||||
+
|
||||
+The VDEC IP is composed of the following blocks :
|
||||
+
|
||||
+- ESPARSER is a bitstream parser that outputs to a VIFIFO. Further VDEC blocks
|
||||
+then feed from this VIFIFO.
|
||||
+- VDEC_1 can decode MPEG-1, MPEG-2, MPEG-4 part 2, H.263, H.264.
|
||||
+- VDEC_2 is used as a helper for corner cases like H.264 4K on older SoCs.
|
||||
+It is not handled by this driver.
|
||||
+- VDEC_HCODEC is the H.264 encoding block. It is not handled by this driver.
|
||||
+- VDEC_HEVC can decode HEVC and VP9.
|
||||
+
|
||||
+Device Tree Bindings:
|
||||
+---------------------
|
||||
+
|
||||
+VDEC: Video Decoder
|
||||
+--------------------------
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: value should be different for each SoC family as :
|
||||
+ - GXBB (S905) : "amlogic,gxbb-vdec"
|
||||
+ - GXL (S905X, S905D) : "amlogic,gxl-vdec"
|
||||
+ - GXM (S912) : "amlogic,gxm-vdec"
|
||||
+- reg: base address and size of he following memory-mapped regions :
|
||||
+ - dos
|
||||
+ - esparser
|
||||
+- reg-names: should contain the names of the previous memory regions
|
||||
+- interrupts: should contain the vdec and esparser IRQs.
|
||||
+- amlogic,ao-sysctrl: should point to the AOBUS sysctrl node
|
||||
+- amlogic,canvas: should point to a canvas provider node
|
||||
+- clocks: should contain the following clocks :
|
||||
+ - dos_parser
|
||||
+ - dos
|
||||
+ - vdec_1
|
||||
+ - vdec_hevc
|
||||
+- clock-names: should contain the names of the previous clocks
|
||||
+- resets: should contain the parser reset.
|
||||
+- reset-names: should be "esparser".
|
||||
+
|
||||
+Example:
|
||||
+
|
||||
+vdec: video-decoder@c8820000 {
|
||||
+ compatible = "amlogic,gxbb-vdec";
|
||||
+ reg = <0x0 0xc8820000 0x0 0x10000>,
|
||||
+ <0x0 0xc110a580 0x0 0xe4>;
|
||||
+ reg-names = "dos", "esparser";
|
||||
+
|
||||
+ interrupts = <GIC_SPI 44 IRQ_TYPE_EDGE_RISING>,
|
||||
+ <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>;
|
||||
+
|
||||
+ amlogic,ao-sysctrl = <&sysctrl_AO>;
|
||||
+ amlogic,canvas = <&canvas>;
|
||||
+
|
||||
+ clocks = <&clkc CLKID_DOS_PARSER>,
|
||||
+ <&clkc CLKID_DOS>,
|
||||
+ <&clkc CLKID_VDEC_1>,
|
||||
+ <&clkc CLKID_VDEC_HEVC>;
|
||||
+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc";
|
||||
+
|
||||
+ resets = <&reset RESET_PARSER>;
|
||||
+ reset-names = "esparser";
|
||||
+};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,36 @@
|
||||
From b73062fd0c0c9630ad00ec5c0e9880798a994875 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:24:02 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson-gx: add vdec entry
|
||||
|
||||
Add the video decoder dts entry
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
index 737b741df0355..d9e0fea71dbe3 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -410,6 +410,19 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ vdec: video-decoder@c8820000 {
|
||||
+ compatible = "amlogic,gx-vdec";
|
||||
+ reg = <0x0 0xc8820000 0x0 0x10000>,
|
||||
+ <0x0 0xc110a580 0x0 0xe4>;
|
||||
+ reg-names = "dos", "esparser";
|
||||
+
|
||||
+ interrupts = <GIC_SPI 44 IRQ_TYPE_EDGE_RISING>,
|
||||
+ <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>;
|
||||
+
|
||||
+ amlogic,ao-sysctrl = <&sysctrl_AO>;
|
||||
+ amlogic,canvas = <&canvas>;
|
||||
+ };
|
||||
+
|
||||
periphs: periphs@c8834000 {
|
||||
compatible = "simple-bus";
|
||||
reg = <0x0 0xc8834000 0x0 0x2000>;
|
@ -0,0 +1,64 @@
|
||||
From c7b0311f4676661ad445f9e36c669886f1bc7835 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:24:22 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson: add vdec entries
|
||||
|
||||
This enables the video decoder for gxbb, gxl and gxm chips
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 11 +++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 11 +++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 4 ++++
|
||||
3 files changed, 26 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 98cbba6809caa..daee53a755d75 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -774,3 +774,14 @@
|
||||
compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
+
|
||||
+&vdec {
|
||||
+ compatible = "amlogic,gxbb-vdec";
|
||||
+ clocks = <&clkc CLKID_DOS_PARSER>,
|
||||
+ <&clkc CLKID_DOS>,
|
||||
+ <&clkc CLKID_VDEC_1>,
|
||||
+ <&clkc CLKID_VDEC_HEVC>;
|
||||
+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc";
|
||||
+ resets = <&reset RESET_PARSER>;
|
||||
+ reset-names = "esparser";
|
||||
+};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index c87a80e9bcc6a..bfd65d1a89591 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -775,3 +775,14 @@
|
||||
compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
+
|
||||
+&vdec {
|
||||
+ compatible = "amlogic,gxl-vdec";
|
||||
+ clocks = <&clkc CLKID_DOS_PARSER>,
|
||||
+ <&clkc CLKID_DOS>,
|
||||
+ <&clkc CLKID_VDEC_1>,
|
||||
+ <&clkc CLKID_VDEC_HEVC>;
|
||||
+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc";
|
||||
+ resets = <&reset RESET_PARSER>;
|
||||
+ reset-names = "esparser";
|
||||
+};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
index 247888d68a3aa..2f356495be5ef 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
@@ -117,3 +117,7 @@
|
||||
&dwc3 {
|
||||
phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>;
|
||||
};
|
||||
+
|
||||
+&vdec {
|
||||
+ compatible = "amlogic,gxm-vdec";
|
||||
+};
|
@ -0,0 +1,466 @@
|
||||
From 9d2683700060a36200da3b296671485b7fec747f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:42:56 +0200
|
||||
Subject: [PATCH] media: meson: vdec: add H.264 decoding support
|
||||
|
||||
Add support for V4L2_PIX_FMT_H264
|
||||
---
|
||||
drivers/media/platform/meson/vdec/Makefile | 2 +-
|
||||
.../media/platform/meson/vdec/codec_h264.c | 354 ++++++++++++++++++
|
||||
.../media/platform/meson/vdec/codec_h264.h | 13 +
|
||||
.../media/platform/meson/vdec/vdec_platform.c | 31 ++
|
||||
4 files changed, 399 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/media/platform/meson/vdec/codec_h264.c
|
||||
create mode 100644 drivers/media/platform/meson/vdec/codec_h264.h
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
|
||||
index 6bea129084b76..711d990c760e0 100644
|
||||
--- a/drivers/media/platform/meson/vdec/Makefile
|
||||
+++ b/drivers/media/platform/meson/vdec/Makefile
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
|
||||
meson-vdec-objs += vdec_1.o
|
||||
-meson-vdec-objs += codec_mpeg12.o
|
||||
+meson-vdec-objs += codec_mpeg12.o codec_h264.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_h264.c b/drivers/media/platform/meson/vdec/codec_h264.c
|
||||
new file mode 100644
|
||||
index 0000000000000..7c47ec35efa54
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_h264.c
|
||||
@@ -0,0 +1,354 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#include <media/v4l2-mem2mem.h>
|
||||
+#include <media/videobuf2-dma-contig.h>
|
||||
+
|
||||
+#include "vdec_helpers.h"
|
||||
+#include "dos_regs.h"
|
||||
+
|
||||
+#define SIZE_EXT_FW (20 * SZ_1K)
|
||||
+#define SIZE_WORKSPACE 0x1ee000
|
||||
+#define SIZE_SEI (8 * SZ_1K)
|
||||
+
|
||||
+/* Offset added by the firmware which must be substracted
|
||||
+ * from the workspace phyaddr
|
||||
+ */
|
||||
+#define WORKSPACE_BUF_OFFSET 0x1000000
|
||||
+
|
||||
+#define SEI_DATA_READY BIT(15)
|
||||
+
|
||||
+/* ISR status */
|
||||
+#define CMD_SET_PARAM 1
|
||||
+#define CMD_FRAMES_READY 2
|
||||
+#define CMD_FATAL_ERROR 6
|
||||
+#define CMD_BAD_WIDTH 7
|
||||
+#define CMD_BAD_HEIGHT 8
|
||||
+
|
||||
+/* Picture type */
|
||||
+#define PIC_SINGLE_FRAME 0
|
||||
+#define PIC_TOP_BOT_TOP 1
|
||||
+#define PIC_BOT_TOP_BOT 2
|
||||
+#define PIC_DOUBLE_FRAME 3
|
||||
+#define PIC_TRIPLE_FRAME 4
|
||||
+#define PIC_TOP_BOT 5
|
||||
+#define PIC_BOT_TOP 6
|
||||
+#define PIC_INVALID 7
|
||||
+
|
||||
+/* Size of Motion Vector per macroblock */
|
||||
+#define MB_MV_SIZE 96
|
||||
+
|
||||
+struct codec_h264 {
|
||||
+ /* H.264 decoder requires an extended firmware */
|
||||
+ void *ext_fw_vaddr;
|
||||
+ dma_addr_t ext_fw_paddr;
|
||||
+
|
||||
+ /* Buffer for the H.264 Workspace */
|
||||
+ void *workspace_vaddr;
|
||||
+ dma_addr_t workspace_paddr;
|
||||
+
|
||||
+ /* Buffer for the H.264 references MV */
|
||||
+ void *ref_vaddr;
|
||||
+ dma_addr_t ref_paddr;
|
||||
+ u32 ref_size;
|
||||
+
|
||||
+ /* Buffer for parsed SEI data */
|
||||
+ void *sei_vaddr;
|
||||
+ dma_addr_t sei_paddr;
|
||||
+
|
||||
+ int received_0;
|
||||
+};
|
||||
+
|
||||
+static int codec_h264_can_recycle(struct amvdec_core *core)
|
||||
+{
|
||||
+ return !amvdec_read_dos(core, AV_SCRATCH_7) ||
|
||||
+ !amvdec_read_dos(core, AV_SCRATCH_8);
|
||||
+}
|
||||
+
|
||||
+static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx)
|
||||
+{
|
||||
+ /* Tell the decoder he can recycle this buffer.
|
||||
+ * AV_SCRATCH_8 serves the same purpose.
|
||||
+ */
|
||||
+ if (!amvdec_read_dos(core, AV_SCRATCH_7))
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1);
|
||||
+ else
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1);
|
||||
+}
|
||||
+
|
||||
+static int codec_h264_start(struct amvdec_session *sess) {
|
||||
+ u32 workspace_offset;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+
|
||||
+ /* Allocate some memory for the H.264 decoder's state */
|
||||
+ h264->workspace_vaddr =
|
||||
+ dma_alloc_coherent(core->dev, SIZE_WORKSPACE, &h264->workspace_paddr, GFP_KERNEL);
|
||||
+ if (!h264->workspace_vaddr) {
|
||||
+ dev_err(core->dev, "Failed to alloc H.264 Workspace\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ /* Allocate some memory for the H.264 SEI dump */
|
||||
+ h264->sei_vaddr =
|
||||
+ dma_alloc_coherent(core->dev, SIZE_SEI, &h264->sei_paddr, GFP_KERNEL);
|
||||
+ if (!h264->sei_vaddr) {
|
||||
+ dev_err(core->dev, "Failed to alloc H.264 SEI\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6));
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_CTRL, 0);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_0, 0);
|
||||
+
|
||||
+ workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET;
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr - workspace_offset);
|
||||
+
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_7, 0);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_8, 0);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_9, 0);
|
||||
+
|
||||
+ /* Enable "error correction" */
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_F, (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) | BIT(4) | BIT(7));
|
||||
+
|
||||
+ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int codec_h264_stop(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ if (h264->ext_fw_vaddr)
|
||||
+ dma_free_coherent(core->dev, SIZE_EXT_FW,
|
||||
+ h264->ext_fw_vaddr, h264->ext_fw_paddr);
|
||||
+
|
||||
+ if (h264->workspace_vaddr)
|
||||
+ dma_free_coherent(core->dev, SIZE_WORKSPACE,
|
||||
+ h264->workspace_vaddr, h264->workspace_paddr);
|
||||
+
|
||||
+ if (h264->ref_vaddr)
|
||||
+ dma_free_coherent(core->dev, h264->ref_size,
|
||||
+ h264->ref_vaddr, h264->ref_paddr);
|
||||
+
|
||||
+ if (h264->sei_vaddr)
|
||||
+ dma_free_coherent(core->dev, SIZE_SEI,
|
||||
+ h264->sei_vaddr, h264->sei_paddr);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int codec_h264_load_extended_firmware(struct amvdec_session *sess, const u8 *data, u32 len)
|
||||
+{
|
||||
+ struct codec_h264 *h264;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ h264 = kzalloc(sizeof(*h264), GFP_KERNEL);
|
||||
+ if (!h264)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ sess->priv = h264;
|
||||
+
|
||||
+ if (len < SIZE_EXT_FW)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW,
|
||||
+ &h264->ext_fw_paddr, GFP_KERNEL);
|
||||
+ if (!h264->ext_fw_vaddr) {
|
||||
+ dev_err(core->dev, "Failed to alloc H.264 extended fw\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Configure the H.264 decoder when the esparser finished parsing
|
||||
+ * the first keyframe
|
||||
+ */
|
||||
+static void codec_h264_set_param(struct amvdec_session *sess) {
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ u32 max_reference_size;
|
||||
+ u32 parsed_info, mb_width, mb_height, mb_total;
|
||||
+ u32 actual_dpb_size = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
|
||||
+ u32 max_dpb_size = 4;
|
||||
+
|
||||
+ sess->keyframe_found = 1;
|
||||
+
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_7, 0);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_8, 0);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_9, 0);
|
||||
+
|
||||
+ parsed_info = amvdec_read_dos(core, AV_SCRATCH_1);
|
||||
+
|
||||
+ /* Total number of 16x16 macroblocks */
|
||||
+ mb_total = (parsed_info >> 8) & 0xffff;
|
||||
+
|
||||
+ /* Number of macroblocks per line */
|
||||
+ mb_width = parsed_info & 0xff;
|
||||
+
|
||||
+ /* Number of macroblock lines */
|
||||
+ mb_height = mb_total / mb_width;
|
||||
+
|
||||
+ max_reference_size = (parsed_info >> 24) & 0x7f;
|
||||
+
|
||||
+ /* Align to a multiple of 4 macroblocks */
|
||||
+ mb_width = ALIGN(mb_width, 4);
|
||||
+ mb_height = ALIGN(mb_height, 4);
|
||||
+ mb_total = mb_width * mb_height;
|
||||
+
|
||||
+ amvdec_set_canvases(sess, (u32[]){ ANC0_CANVAS_ADDR, 0 },
|
||||
+ (u32[]){ 24, 0 });
|
||||
+
|
||||
+ if (max_reference_size > max_dpb_size)
|
||||
+ max_dpb_size = max_reference_size;
|
||||
+
|
||||
+ max_reference_size++;
|
||||
+ dev_dbg(core->dev,
|
||||
+ "max_ref_size = %u; max_dpb_size = %u; actual_dpb_size = %u\n",
|
||||
+ max_reference_size, max_dpb_size, actual_dpb_size);
|
||||
+
|
||||
+ h264->ref_size = mb_total * MB_MV_SIZE * max_reference_size;
|
||||
+ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size,
|
||||
+ &h264->ref_paddr, GFP_KERNEL);
|
||||
+ if (!h264->ref_vaddr) {
|
||||
+ dev_err(core->dev, "Failed to alloc refs (%u)\n",
|
||||
+ h264->ref_size);
|
||||
+ amvdec_abort(sess);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Address to store the references' MVs */
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr);
|
||||
+ /* End of ref MV */
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size);
|
||||
+
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_0, (max_reference_size << 24) |
|
||||
+ (actual_dpb_size << 16) |
|
||||
+ (max_dpb_size << 8));
|
||||
+}
|
||||
+
|
||||
+static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ int error_count;
|
||||
+ int num_frames;
|
||||
+ int i;
|
||||
+
|
||||
+ error_count = amvdec_read_dos(core, AV_SCRATCH_D);
|
||||
+ num_frames = (status >> 8) & 0xff;
|
||||
+ if (error_count) {
|
||||
+ dev_warn(core->dev,
|
||||
+ "decoder error(s) happened, count %d\n", error_count);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_D, 0);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num_frames; i++) {
|
||||
+ u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4);
|
||||
+ u32 buffer_index = frame_status & 0x1f;
|
||||
+ u32 error = frame_status & 0x200;
|
||||
+ u32 pic_struct = (frame_status >> 5) & 0x7;
|
||||
+ u32 field = V4L2_FIELD_NONE;
|
||||
+
|
||||
+ /* A buffer decode error means it was decoded,
|
||||
+ * but part of the picture will have artifacts.
|
||||
+ * Typical reason is a temporarily corrupted bitstream
|
||||
+ */
|
||||
+ if (error)
|
||||
+ dev_info(core->dev, "Buffer %d decode error\n",
|
||||
+ buffer_index);
|
||||
+
|
||||
+ if (pic_struct == PIC_TOP_BOT)
|
||||
+ field = V4L2_FIELD_INTERLACED_TB;
|
||||
+ else if (pic_struct == PIC_BOT_TOP)
|
||||
+ field = V4L2_FIELD_INTERLACED_BT;
|
||||
+
|
||||
+ amvdec_dst_buf_done_idx(sess, buffer_index, field);
|
||||
+
|
||||
+ if (field != V4L2_FIELD_NONE && !h264->received_0)
|
||||
+ amvdec_rm_first_ts(sess);
|
||||
+
|
||||
+ h264->received_0 = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_h264 *h264 = sess->priv;
|
||||
+ u32 status;
|
||||
+ u32 size;
|
||||
+ u8 cmd;
|
||||
+
|
||||
+ status = amvdec_read_dos(core, AV_SCRATCH_0);
|
||||
+ cmd = status & 0xff;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case CMD_SET_PARAM:
|
||||
+ codec_h264_set_param(sess);
|
||||
+ break;
|
||||
+ case CMD_FRAMES_READY:
|
||||
+ codec_h264_frames_ready(sess, status);
|
||||
+ break;
|
||||
+ case CMD_FATAL_ERROR:
|
||||
+ dev_err(core->dev, "H.264 decoder fatal error\n");
|
||||
+ goto abort;
|
||||
+ case CMD_BAD_WIDTH:
|
||||
+ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
|
||||
+ dev_err(core->dev, "Unsupported video width: %u\n", size);
|
||||
+ goto abort;
|
||||
+ case CMD_BAD_HEIGHT:
|
||||
+ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
|
||||
+ dev_err(core->dev, "Unsupported video height: %u\n", size);
|
||||
+ goto abort;
|
||||
+ case 0:
|
||||
+ h264->received_0 = 1;
|
||||
+ break;
|
||||
+ case 9: /* Unused but not worth printing for */
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (cmd && cmd != CMD_SET_PARAM)
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_0, 0);
|
||||
+
|
||||
+ /* Decoder has some SEI data for us ; ignore */
|
||||
+ if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY)
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_J, 0);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+abort:
|
||||
+ amvdec_abort(sess);
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t codec_h264_isr(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
|
||||
+
|
||||
+ return IRQ_WAKE_THREAD;
|
||||
+}
|
||||
+
|
||||
+struct amvdec_codec_ops codec_h264_ops = {
|
||||
+ .start = codec_h264_start,
|
||||
+ .stop = codec_h264_stop,
|
||||
+ .load_extended_firmware = codec_h264_load_extended_firmware,
|
||||
+ .isr = codec_h264_isr,
|
||||
+ .threaded_isr = codec_h264_threaded_isr,
|
||||
+ .can_recycle = codec_h264_can_recycle,
|
||||
+ .recycle = codec_h264_recycle,
|
||||
+};
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_h264.h b/drivers/media/platform/meson/vdec/codec_h264.h
|
||||
new file mode 100644
|
||||
index 0000000000000..7a1597611faff
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_h264.h
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_CODEC_H264_H_
|
||||
+#define __MESON_VDEC_CODEC_H264_H_
|
||||
+
|
||||
+#include "vdec.h"
|
||||
+
|
||||
+extern struct amvdec_codec_ops codec_h264_ops;
|
||||
+
|
||||
+#endif
|
||||
\ No newline at end of file
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
index 46eeb7426f547..9f7872feef74d 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
@@ -9,9 +9,20 @@
|
||||
|
||||
#include "vdec_1.h"
|
||||
#include "codec_mpeg12.h"
|
||||
+#include "codec_h264.h"
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 21,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/gxbb/vh264_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -36,6 +47,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 21,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/gxl/vh264_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -60,6 +81,16 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_H264,
|
||||
+ .min_buffers = 21,
|
||||
+ .max_buffers = 24,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_h264_ops,
|
||||
+ .firmware_path = "meson/gxm/vh264_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG1,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
@ -0,0 +1,304 @@
|
||||
From 4e628eee07aed9d006a4c4b4a75d41f05924b4c8 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 16:01:55 +0200
|
||||
Subject: [PATCH] media: meson: vdec: add MPEG4 decoding support
|
||||
|
||||
Add support for V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID and
|
||||
V4L2_PIX_FMT_H.263
|
||||
---
|
||||
drivers/media/platform/meson/vdec/Makefile | 2 +-
|
||||
.../media/platform/meson/vdec/codec_mpeg4.c | 131 ++++++++++++++++++
|
||||
.../media/platform/meson/vdec/codec_mpeg4.h | 13 ++
|
||||
.../media/platform/meson/vdec/vdec_platform.c | 91 ++++++++++++
|
||||
4 files changed, 236 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.c
|
||||
create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.h
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
|
||||
index 711d990c760e0..f167a61acb36d 100644
|
||||
--- a/drivers/media/platform/meson/vdec/Makefile
|
||||
+++ b/drivers/media/platform/meson/vdec/Makefile
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
|
||||
meson-vdec-objs += vdec_1.o
|
||||
-meson-vdec-objs += codec_mpeg12.o codec_h264.o
|
||||
+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.c b/drivers/media/platform/meson/vdec/codec_mpeg4.c
|
||||
new file mode 100644
|
||||
index 0000000000000..c6db2640c91a7
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.c
|
||||
@@ -0,0 +1,131 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#include <media/v4l2-mem2mem.h>
|
||||
+#include <media/videobuf2-dma-contig.h>
|
||||
+
|
||||
+#include "vdec_helpers.h"
|
||||
+#include "dos_regs.h"
|
||||
+
|
||||
+#define SIZE_WORKSPACE SZ_1M
|
||||
+/* Offset added by firmware, to substract from workspace paddr */
|
||||
+#define DCAC_BUFF_START_IP 0x02b00000
|
||||
+
|
||||
+/* map FW registers to known MPEG4 functions */
|
||||
+#define MP4_PIC_RATIO AV_SCRATCH_5
|
||||
+#define MP4_ERR_COUNT AV_SCRATCH_6
|
||||
+#define MP4_PIC_WH AV_SCRATCH_7
|
||||
+#define MREG_BUFFERIN AV_SCRATCH_8
|
||||
+#define MREG_BUFFEROUT AV_SCRATCH_9
|
||||
+#define MP4_NOT_CODED_CNT AV_SCRATCH_A
|
||||
+#define MP4_VOP_TIME_INC AV_SCRATCH_B
|
||||
+#define MP4_OFFSET_REG AV_SCRATCH_C
|
||||
+#define MP4_SYS_RATE AV_SCRATCH_E
|
||||
+#define MEM_OFFSET_REG AV_SCRATCH_F
|
||||
+#define MREG_FATAL_ERROR AV_SCRATCH_L
|
||||
+
|
||||
+struct codec_mpeg4 {
|
||||
+ /* Buffer for the MPEG4 Workspace */
|
||||
+ void *workspace_vaddr;
|
||||
+ dma_addr_t workspace_paddr;
|
||||
+};
|
||||
+
|
||||
+static int codec_mpeg4_can_recycle(struct amvdec_core *core)
|
||||
+{
|
||||
+ return !amvdec_read_dos(core, MREG_BUFFERIN);
|
||||
+}
|
||||
+
|
||||
+static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx)
|
||||
+{
|
||||
+ amvdec_write_dos(core, MREG_BUFFERIN, ~(1 << buf_idx));
|
||||
+}
|
||||
+
|
||||
+static int codec_mpeg4_start(struct amvdec_session *sess) {
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+ struct codec_mpeg4 *mpeg4 = sess->priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL);
|
||||
+ if (!mpeg4)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ sess->priv = mpeg4;
|
||||
+
|
||||
+ /* Allocate some memory for the MPEG4 decoder's state */
|
||||
+ mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
|
||||
+ &mpeg4->workspace_paddr,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!mpeg4->workspace_vaddr) {
|
||||
+ dev_err(core->dev, "Failed to request MPEG4 Workspace\n");
|
||||
+ ret = -ENOMEM;
|
||||
+ goto free_mpeg4;
|
||||
+ }
|
||||
+
|
||||
+ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 },
|
||||
+ (u32[]){ 4, 4, 0 });
|
||||
+
|
||||
+ amvdec_write_dos(core, MEM_OFFSET_REG,
|
||||
+ mpeg4->workspace_paddr - DCAC_BUFF_START_IP);
|
||||
+ amvdec_write_dos(core, PSCALE_CTRL, 0);
|
||||
+ amvdec_write_dos(core, MP4_NOT_CODED_CNT, 0);
|
||||
+ amvdec_write_dos(core, MREG_BUFFERIN, 0);
|
||||
+ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
|
||||
+ amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
|
||||
+ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+free_mpeg4:
|
||||
+ kfree(mpeg4);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int codec_mpeg4_stop(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct codec_mpeg4 *mpeg4 = sess->priv;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ if (mpeg4->workspace_vaddr) {
|
||||
+ dma_free_coherent(core->dev, SIZE_WORKSPACE,
|
||||
+ mpeg4->workspace_vaddr,
|
||||
+ mpeg4->workspace_paddr);
|
||||
+ mpeg4->workspace_vaddr = 0;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess)
|
||||
+{
|
||||
+ u32 reg;
|
||||
+ u32 buffer_index;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
|
||||
+ if (reg == 1)
|
||||
+ dev_err(core->dev, "mpeg4 fatal error\n");
|
||||
+
|
||||
+ reg = amvdec_read_dos(core, MREG_BUFFEROUT);
|
||||
+ if (reg) {
|
||||
+ sess->keyframe_found = 1;
|
||||
+ amvdec_read_dos(core, MP4_NOT_CODED_CNT);
|
||||
+ amvdec_read_dos(core, MP4_VOP_TIME_INC);
|
||||
+ buffer_index = reg & 0x7;
|
||||
+ amvdec_dst_buf_done_idx(sess, buffer_index, V4L2_FIELD_NONE);
|
||||
+ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
|
||||
+ }
|
||||
+
|
||||
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+struct amvdec_codec_ops codec_mpeg4_ops = {
|
||||
+ .start = codec_mpeg4_start,
|
||||
+ .stop = codec_mpeg4_stop,
|
||||
+ .isr = codec_mpeg4_isr,
|
||||
+ .can_recycle = codec_mpeg4_can_recycle,
|
||||
+ .recycle = codec_mpeg4_recycle,
|
||||
+};
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.h b/drivers/media/platform/meson/vdec/codec_mpeg4.h
|
||||
new file mode 100644
|
||||
index 0000000000000..b91b264131854
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.h
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_CODEC_MPEG4_H_
|
||||
+#define __MESON_VDEC_CODEC_MPEG4_H_
|
||||
+
|
||||
+#include "vdec.h"
|
||||
+
|
||||
+extern struct amvdec_codec_ops codec_mpeg4_ops;
|
||||
+
|
||||
+#endif
|
||||
\ No newline at end of file
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
index 9f7872feef74d..135d7566d716a 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
@@ -10,9 +10,40 @@
|
||||
#include "vdec_1.h"
|
||||
#include "codec_mpeg12.h"
|
||||
#include "codec_h264.h"
|
||||
+#include "codec_mpeg4.h"
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_MPEG4,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/vmpeg4_mc_5",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
+ .pixfmt = V4L2_PIX_FMT_H263,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/h263_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
+ .pixfmt = V4L2_PIX_FMT_XVID,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/vmpeg4_mc_5",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_H264,
|
||||
.min_buffers = 21,
|
||||
.max_buffers = 24,
|
||||
@@ -47,6 +78,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_MPEG4,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/vmpeg4_mc_5",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
+ .pixfmt = V4L2_PIX_FMT_H263,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/h263_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
+ .pixfmt = V4L2_PIX_FMT_XVID,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/vmpeg4_mc_5",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_H264,
|
||||
.min_buffers = 21,
|
||||
.max_buffers = 24,
|
||||
@@ -81,6 +142,36 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_MPEG4,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/vmpeg4_mc_5",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
+ .pixfmt = V4L2_PIX_FMT_H263,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/h263_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
+ .pixfmt = V4L2_PIX_FMT_XVID,
|
||||
+ .min_buffers = 8,
|
||||
+ .max_buffers = 8,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mpeg4_ops,
|
||||
+ .firmware_path = "meson/gx/vmpeg4_mc_5",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_H264,
|
||||
.min_buffers = 21,
|
||||
.max_buffers = 24,
|
@ -0,0 +1,249 @@
|
||||
From 920fefae2df25f616552de3c842965f671dd9bae Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 16:05:28 +0200
|
||||
Subject: [PATCH] media: meson: vdec: add MJPEG decoding support
|
||||
|
||||
Add support for V4L2_PIX_FMT_MJPEG
|
||||
---
|
||||
drivers/media/platform/meson/vdec/Makefile | 2 +-
|
||||
.../media/platform/meson/vdec/codec_mjpeg.c | 137 ++++++++++++++++++
|
||||
.../media/platform/meson/vdec/codec_mjpeg.h | 13 ++
|
||||
.../media/platform/meson/vdec/vdec_platform.c | 31 ++++
|
||||
4 files changed, 182 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.c
|
||||
create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.h
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
|
||||
index f167a61acb36d..20c23f9015ebd 100644
|
||||
--- a/drivers/media/platform/meson/vdec/Makefile
|
||||
+++ b/drivers/media/platform/meson/vdec/Makefile
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
|
||||
meson-vdec-objs += vdec_1.o
|
||||
-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o
|
||||
+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.c b/drivers/media/platform/meson/vdec/codec_mjpeg.c
|
||||
new file mode 100644
|
||||
index 0000000000000..f632c51c8fffe
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.c
|
||||
@@ -0,0 +1,137 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#include <media/v4l2-mem2mem.h>
|
||||
+#include <media/videobuf2-dma-contig.h>
|
||||
+
|
||||
+#include "vdec_helpers.h"
|
||||
+#include "dos_regs.h"
|
||||
+
|
||||
+/* map FW registers to known MJPEG functions */
|
||||
+#define MREG_DECODE_PARAM AV_SCRATCH_2
|
||||
+#define MREG_TO_AMRISC AV_SCRATCH_8
|
||||
+#define MREG_FROM_AMRISC AV_SCRATCH_9
|
||||
+
|
||||
+static int codec_mjpeg_can_recycle(struct amvdec_core *core)
|
||||
+{
|
||||
+ return !amvdec_read_dos(core, MREG_TO_AMRISC);
|
||||
+}
|
||||
+
|
||||
+static void codec_mjpeg_recycle(struct amvdec_core *core, u32 buf_idx)
|
||||
+{
|
||||
+ amvdec_write_dos(core, MREG_TO_AMRISC, buf_idx + 1);
|
||||
+}
|
||||
+
|
||||
+/* 4 point triangle */
|
||||
+static const uint32_t filt_coef[] = {
|
||||
+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
|
||||
+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
|
||||
+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
|
||||
+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
|
||||
+ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
|
||||
+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
|
||||
+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
|
||||
+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
|
||||
+ 0x10303010
|
||||
+};
|
||||
+
|
||||
+static void codec_mjpeg_init_scaler(struct amvdec_core *core)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ /* PSCALE cbus bmem enable */
|
||||
+ amvdec_write_dos(core, PSCALE_CTRL, 0xc000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 0);
|
||||
+ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) {
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, filt_coef[i]);
|
||||
+ }
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 74);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 82);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 78);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 86);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 73);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 81);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 77);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 85);
|
||||
+ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
|
||||
+
|
||||
+ amvdec_write_dos(core, PSCALE_RST, 0x7);
|
||||
+ amvdec_write_dos(core, PSCALE_RST, 0);
|
||||
+}
|
||||
+
|
||||
+static int codec_mjpeg_start(struct amvdec_session *sess)
|
||||
+{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_0, 12);
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_1, 0x031a);
|
||||
+
|
||||
+ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_4, 0 },
|
||||
+ (u32[]){ 4, 0 });
|
||||
+ codec_mjpeg_init_scaler(core);
|
||||
+
|
||||
+ amvdec_write_dos(core, MREG_TO_AMRISC, 0);
|
||||
+ amvdec_write_dos(core, MREG_FROM_AMRISC, 0);
|
||||
+ amvdec_write_dos(core, MCPU_INTR_MSK, 0xffff);
|
||||
+ amvdec_write_dos(core, MREG_DECODE_PARAM,
|
||||
+ (sess->height << 4) | 0x8000);
|
||||
+ amvdec_write_dos(core, VDEC_ASSIST_AMR1_INT8, 8);
|
||||
+
|
||||
+ /* Intra-only codec */
|
||||
+ sess->keyframe_found = 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int codec_mjpeg_stop(struct amvdec_session *sess)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t codec_mjpeg_isr(struct amvdec_session *sess)
|
||||
+{
|
||||
+ u32 reg;
|
||||
+ u32 buffer_index;
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
+
|
||||
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
|
||||
+
|
||||
+ reg = amvdec_read_dos(core, MREG_FROM_AMRISC);
|
||||
+ if (!(reg & 0x7))
|
||||
+ return IRQ_HANDLED;
|
||||
+
|
||||
+ buffer_index = ((reg & 0x7) - 1) & 3;
|
||||
+ amvdec_dst_buf_done_idx(sess, buffer_index, V4L2_FIELD_NONE);
|
||||
+
|
||||
+ amvdec_write_dos(core, MREG_FROM_AMRISC, 0);
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+struct amvdec_codec_ops codec_mjpeg_ops = {
|
||||
+ .start = codec_mjpeg_start,
|
||||
+ .stop = codec_mjpeg_stop,
|
||||
+ .isr = codec_mjpeg_isr,
|
||||
+ .can_recycle = codec_mjpeg_can_recycle,
|
||||
+ .recycle = codec_mjpeg_recycle,
|
||||
+};
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.h b/drivers/media/platform/meson/vdec/codec_mjpeg.h
|
||||
new file mode 100644
|
||||
index 0000000000000..cc1cf731050d1
|
||||
--- /dev/null
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.h
|
||||
@@ -0,0 +1,13 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __MESON_VDEC_CODEC_MJPEG_H_
|
||||
+#define __MESON_VDEC_CODEC_MJPEG_H_
|
||||
+
|
||||
+#include "vdec.h"
|
||||
+
|
||||
+extern struct amvdec_codec_ops codec_mjpeg_ops;
|
||||
+
|
||||
+#endif
|
||||
\ No newline at end of file
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
index 135d7566d716a..1181832b5fe1e 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
@@ -11,9 +11,20 @@
|
||||
#include "codec_mpeg12.h"
|
||||
#include "codec_h264.h"
|
||||
#include "codec_mpeg4.h"
|
||||
+#include "codec_mjpeg.h"
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_MJPEG,
|
||||
+ .min_buffers = 4,
|
||||
+ .max_buffers = 4,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mjpeg_ops,
|
||||
+ .firmware_path = "meson/gx/vmjpeg_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG4,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -78,6 +89,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_MJPEG,
|
||||
+ .min_buffers = 4,
|
||||
+ .max_buffers = 4,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mjpeg_ops,
|
||||
+ .firmware_path = "meson/gx/vmjpeg_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG4,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
||||
@@ -142,6 +163,16 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
|
||||
static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
{
|
||||
+ .pixfmt = V4L2_PIX_FMT_MJPEG,
|
||||
+ .min_buffers = 4,
|
||||
+ .max_buffers = 4,
|
||||
+ .max_width = 1920,
|
||||
+ .max_height = 1080,
|
||||
+ .vdec_ops = &vdec_1_ops,
|
||||
+ .codec_ops = &codec_mjpeg_ops,
|
||||
+ .firmware_path = "meson/gx/vmjpeg_mc",
|
||||
+ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
|
||||
+ }, {
|
||||
.pixfmt = V4L2_PIX_FMT_MPEG4,
|
||||
.min_buffers = 8,
|
||||
.max_buffers = 8,
|
@ -0,0 +1,26 @@
|
||||
From 4f40ed63fe484c78d02e3d0583a7f44f815980f3 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 18:36:09 +0200
|
||||
Subject: [PATCH] media: videodev2.h; Add Amlogic compressed format
|
||||
|
||||
Add V4L2_PIX_FMT_AM21C which is a lossless, compressed framebuffer
|
||||
format.
|
||||
|
||||
It is used by the video decoding and the display IP on many Amlogic
|
||||
SoCs.
|
||||
---
|
||||
include/uapi/linux/videodev2.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
|
||||
index 600877be5c229..0568053e3aff9 100644
|
||||
--- a/include/uapi/linux/videodev2.h
|
||||
+++ b/include/uapi/linux/videodev2.h
|
||||
@@ -668,6 +668,7 @@ struct v4l2_pix_format {
|
||||
#define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
|
||||
#define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
|
||||
#define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */
|
||||
+#define V4L2_PIX_FMT_AM21C v4l2_fourcc('A', 'M', '2', '1') /* Amlogic compressed block mode */
|
||||
#define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
|
||||
|
||||
/* 10bit raw bayer packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */
|
@ -0,0 +1,103 @@
|
||||
From 88eb5d85f62d7a41559f3b9c15ec69b07c4ee005 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 18:46:31 +0200
|
||||
Subject: [PATCH] media: meson: vdec: add V4L2_PIX_FMT_AM21C support
|
||||
|
||||
Support the lossless, framebuffer compression format from Amlogic.
|
||||
|
||||
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
---
|
||||
drivers/media/platform/meson/vdec/vdec.c | 7 +++++
|
||||
.../media/platform/meson/vdec/vdec_helpers.c | 31 +++++++++++++++++++
|
||||
.../media/platform/meson/vdec/vdec_helpers.h | 4 +++
|
||||
3 files changed, 42 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c
|
||||
index 32e1e22282970..d5f8fed2886f5 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec.c
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec.c
|
||||
@@ -182,6 +182,9 @@ static int vdec_queue_setup(struct vb2_queue *q,
|
||||
sizes[1] = amvdec_get_output_size(sess) / 4;
|
||||
sizes[2] = amvdec_get_output_size(sess) / 4;
|
||||
*num_planes = 3;
|
||||
+ } else if (pixfmt_cap == V4L2_PIX_FMT_AM21C) {
|
||||
+ sizes[0] = amvdec_am21c_size(sess->width, sess->height);
|
||||
+ *num_planes = 1;
|
||||
}
|
||||
*num_buffers = min(max(*num_buffers, fmt_out->min_buffers),
|
||||
fmt_out->max_buffers);
|
||||
@@ -444,6 +447,10 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
|
||||
get_output_size(pixmp->width, pixmp->height) / 4;
|
||||
pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2;
|
||||
pixmp->num_planes = 3;
|
||||
+ } else if (pixmp->pixelformat == V4L2_PIX_FMT_AM21C) {
|
||||
+ pfmt[0].sizeimage =
|
||||
+ amvdec_am21c_size(pixmp->width, pixmp->height);
|
||||
+ pfmt[0].bytesperline = 0;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c
|
||||
index 6151076297655..1c3a015eb3b33 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec_helpers.c
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec_helpers.c
|
||||
@@ -49,6 +49,33 @@ void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amvdec_write_parser);
|
||||
|
||||
+/* 4 KiB per 64x32 block */
|
||||
+u32 amvdec_am21c_body_size(u32 width, u32 height)
|
||||
+{
|
||||
+ u32 width_64 = ALIGN(width, 64) / 64;
|
||||
+ u32 height_32 = ALIGN(height, 32) / 32;
|
||||
+
|
||||
+ return SZ_4K * width_64 * height_32;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amvdec_am21c_body_size);
|
||||
+
|
||||
+/* 32 bytes per 128x64 block */
|
||||
+u32 amvdec_am21c_head_size(u32 width, u32 height)
|
||||
+{
|
||||
+ u32 width_128 = ALIGN(width, 128) / 128;
|
||||
+ u32 height_64 = ALIGN(height, 64) / 64;
|
||||
+
|
||||
+ return 32 * width_128 * height_64;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amvdec_am21c_head_size);
|
||||
+
|
||||
+u32 amvdec_am21c_size(u32 width, u32 height)
|
||||
+{
|
||||
+ return ALIGN(amvdec_am21c_body_size(width, height) +
|
||||
+ amvdec_am21c_head_size(width, height), SZ_64K);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amvdec_am21c_size);
|
||||
+
|
||||
static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
|
||||
{
|
||||
int ret;
|
||||
@@ -228,6 +255,10 @@ void amvdec_dst_buf_done(struct amvdec_session *sess,
|
||||
vbuf->vb2_buf.planes[1].bytesused = output_size / 4;
|
||||
vbuf->vb2_buf.planes[2].bytesused = output_size / 4;
|
||||
break;
|
||||
+ case V4L2_PIX_FMT_AM21C:
|
||||
+ vbuf->vb2_buf.planes[0].bytesused =
|
||||
+ amvdec_am21c_size(sess->width, sess->height);
|
||||
+ break;
|
||||
}
|
||||
vbuf->vb2_buf.timestamp = tmp->ts;
|
||||
vbuf->sequence = sess->sequence_cap++;
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h
|
||||
index 352c6b4c4b84c..d8a4a2c563af0 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec_helpers.h
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec_helpers.h
|
||||
@@ -26,6 +26,10 @@ void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
|
||||
u32 amvdec_read_parser(struct amvdec_core *core, u32 reg);
|
||||
void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val);
|
||||
|
||||
+u32 amvdec_am21c_body_size(u32 width, u32 height);
|
||||
+u32 amvdec_am21c_head_size(u32 width, u32 height);
|
||||
+u32 amvdec_am21c_size(u32 width, u32 height);
|
||||
+
|
||||
void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx,
|
||||
u32 field);
|
||||
void amvdec_dst_buf_done(struct amvdec_session *sess,
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,127 @@
|
||||
From 36c532fff8000ef7a125b9260753a374ec746426 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Fri, 31 Aug 2018 14:03:23 +0200
|
||||
Subject: [PATCH] mpeg4: fixes & cleanups
|
||||
|
||||
* Remove unused registers
|
||||
* Use constants for bits and masks
|
||||
* abort on fatal error
|
||||
* Don't set sess->priv until the end
|
||||
---
|
||||
.../media/platform/meson/vdec/codec_mpeg4.c | 59 +++++++++++--------
|
||||
1 file changed, 33 insertions(+), 26 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.c b/drivers/media/platform/meson/vdec/codec_mpeg4.c
|
||||
index c6db2640c91a7..b28e3d477df0d 100644
|
||||
--- a/drivers/media/platform/meson/vdec/codec_mpeg4.c
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.c
|
||||
@@ -13,18 +13,16 @@
|
||||
/* Offset added by firmware, to substract from workspace paddr */
|
||||
#define DCAC_BUFF_START_IP 0x02b00000
|
||||
|
||||
-/* map FW registers to known MPEG4 functions */
|
||||
-#define MP4_PIC_RATIO AV_SCRATCH_5
|
||||
-#define MP4_ERR_COUNT AV_SCRATCH_6
|
||||
-#define MP4_PIC_WH AV_SCRATCH_7
|
||||
-#define MREG_BUFFERIN AV_SCRATCH_8
|
||||
-#define MREG_BUFFEROUT AV_SCRATCH_9
|
||||
-#define MP4_NOT_CODED_CNT AV_SCRATCH_A
|
||||
-#define MP4_VOP_TIME_INC AV_SCRATCH_B
|
||||
-#define MP4_OFFSET_REG AV_SCRATCH_C
|
||||
-#define MP4_SYS_RATE AV_SCRATCH_E
|
||||
-#define MEM_OFFSET_REG AV_SCRATCH_F
|
||||
-#define MREG_FATAL_ERROR AV_SCRATCH_L
|
||||
+/* map firmware registers to known MPEG4 functions */
|
||||
+#define MREG_BUFFERIN AV_SCRATCH_8
|
||||
+#define MREG_BUFFEROUT AV_SCRATCH_9
|
||||
+#define MP4_NOT_CODED_CNT AV_SCRATCH_A
|
||||
+#define MEM_OFFSET_REG AV_SCRATCH_F
|
||||
+#define MREG_FATAL_ERROR AV_SCRATCH_L
|
||||
+
|
||||
+#define BUF_IDX_MASK GENMASK(2, 0)
|
||||
+#define INTERLACE_FLAG BIT(7)
|
||||
+#define TOP_FIELD_FIRST_FLAG BIT(6)
|
||||
|
||||
struct codec_mpeg4 {
|
||||
/* Buffer for the MPEG4 Workspace */
|
||||
@@ -39,7 +37,7 @@ static int codec_mpeg4_can_recycle(struct amvdec_core *core)
|
||||
|
||||
static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx)
|
||||
{
|
||||
- amvdec_write_dos(core, MREG_BUFFERIN, ~(1 << buf_idx));
|
||||
+ amvdec_write_dos(core, MREG_BUFFERIN, ~BIT(buf_idx));
|
||||
}
|
||||
|
||||
static int codec_mpeg4_start(struct amvdec_session *sess) {
|
||||
@@ -51,8 +49,6 @@ static int codec_mpeg4_start(struct amvdec_session *sess) {
|
||||
if (!mpeg4)
|
||||
return -ENOMEM;
|
||||
|
||||
- sess->priv = mpeg4;
|
||||
-
|
||||
/* Allocate some memory for the MPEG4 decoder's state */
|
||||
mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
|
||||
&mpeg4->workspace_paddr,
|
||||
@@ -63,6 +59,7 @@ static int codec_mpeg4_start(struct amvdec_session *sess) {
|
||||
goto free_mpeg4;
|
||||
}
|
||||
|
||||
+ /* Canvas regs: AV_SCRATCH_0-AV_SCRATCH_4;AV_SCRATCH_G-AV_SCRATCH_J */
|
||||
amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 },
|
||||
(u32[]){ 4, 4, 0 });
|
||||
|
||||
@@ -75,6 +72,8 @@ static int codec_mpeg4_start(struct amvdec_session *sess) {
|
||||
amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
|
||||
amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
|
||||
|
||||
+ sess->priv = mpeg4;
|
||||
+
|
||||
return 0;
|
||||
|
||||
free_mpeg4:
|
||||
@@ -99,26 +98,34 @@ static int codec_mpeg4_stop(struct amvdec_session *sess)
|
||||
|
||||
static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess)
|
||||
{
|
||||
+ struct amvdec_core *core = sess->core;
|
||||
u32 reg;
|
||||
u32 buffer_index;
|
||||
- struct amvdec_core *core = sess->core;
|
||||
+ u32 field = V4L2_FIELD_NONE;
|
||||
|
||||
reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
|
||||
- if (reg == 1)
|
||||
+ if (reg == 1) {
|
||||
dev_err(core->dev, "mpeg4 fatal error\n");
|
||||
+ amvdec_abort(sess);
|
||||
+ return IRQ_HANDLED;
|
||||
+ }
|
||||
|
||||
reg = amvdec_read_dos(core, MREG_BUFFEROUT);
|
||||
- if (reg) {
|
||||
- sess->keyframe_found = 1;
|
||||
- amvdec_read_dos(core, MP4_NOT_CODED_CNT);
|
||||
- amvdec_read_dos(core, MP4_VOP_TIME_INC);
|
||||
- buffer_index = reg & 0x7;
|
||||
- amvdec_dst_buf_done_idx(sess, buffer_index, V4L2_FIELD_NONE);
|
||||
- amvdec_write_dos(core, MREG_BUFFEROUT, 0);
|
||||
- }
|
||||
+ if (!reg)
|
||||
+ goto end;
|
||||
|
||||
- amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
|
||||
+ sess->keyframe_found = 1;
|
||||
+ buffer_index = reg & BUF_IDX_MASK;
|
||||
+ if (reg & INTERLACE_FLAG)
|
||||
+ field = (reg & TOP_FIELD_FIRST_FLAG) ?
|
||||
+ V4L2_FIELD_INTERLACED_TB :
|
||||
+ V4L2_FIELD_INTERLACED_BT;
|
||||
|
||||
+ amvdec_dst_buf_done_idx(sess, buffer_index, field);
|
||||
+ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
|
||||
+
|
||||
+end:
|
||||
+ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -0,0 +1,117 @@
|
||||
From 89c2edfb991fb85fab722d087e98a40758f8ff8c Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Fri, 31 Aug 2018 14:04:10 +0200
|
||||
Subject: [PATCH] H.264: fixes & cleanups
|
||||
|
||||
* fix GXL and GXM max width/height
|
||||
* 80+ lines
|
||||
* remove unused defines
|
||||
---
|
||||
.../media/platform/meson/vdec/codec_h264.c | 24 +++++++++----------
|
||||
.../media/platform/meson/vdec/vdec_platform.c | 8 +++----
|
||||
2 files changed, 15 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/codec_h264.c b/drivers/media/platform/meson/vdec/codec_h264.c
|
||||
index 7c47ec35efa54..decd3c601cde3 100644
|
||||
--- a/drivers/media/platform/meson/vdec/codec_h264.c
|
||||
+++ b/drivers/media/platform/meson/vdec/codec_h264.c
|
||||
@@ -28,14 +28,8 @@
|
||||
#define CMD_BAD_HEIGHT 8
|
||||
|
||||
/* Picture type */
|
||||
-#define PIC_SINGLE_FRAME 0
|
||||
-#define PIC_TOP_BOT_TOP 1
|
||||
-#define PIC_BOT_TOP_BOT 2
|
||||
-#define PIC_DOUBLE_FRAME 3
|
||||
-#define PIC_TRIPLE_FRAME 4
|
||||
#define PIC_TOP_BOT 5
|
||||
#define PIC_BOT_TOP 6
|
||||
-#define PIC_INVALID 7
|
||||
|
||||
/* Size of Motion Vector per macroblock */
|
||||
#define MB_MV_SIZE 96
|
||||
@@ -84,16 +78,16 @@ static int codec_h264_start(struct amvdec_session *sess) {
|
||||
struct codec_h264 *h264 = sess->priv;
|
||||
|
||||
/* Allocate some memory for the H.264 decoder's state */
|
||||
- h264->workspace_vaddr =
|
||||
- dma_alloc_coherent(core->dev, SIZE_WORKSPACE, &h264->workspace_paddr, GFP_KERNEL);
|
||||
+ h264->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
|
||||
+ &h264->workspace_paddr, GFP_KERNEL);
|
||||
if (!h264->workspace_vaddr) {
|
||||
dev_err(core->dev, "Failed to alloc H.264 Workspace\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate some memory for the H.264 SEI dump */
|
||||
- h264->sei_vaddr =
|
||||
- dma_alloc_coherent(core->dev, SIZE_SEI, &h264->sei_paddr, GFP_KERNEL);
|
||||
+ h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI,
|
||||
+ &h264->sei_paddr, GFP_KERNEL);
|
||||
if (!h264->sei_vaddr) {
|
||||
dev_err(core->dev, "Failed to alloc H.264 SEI\n");
|
||||
return -ENOMEM;
|
||||
@@ -114,7 +108,9 @@ static int codec_h264_start(struct amvdec_session *sess) {
|
||||
amvdec_write_dos(core, AV_SCRATCH_9, 0);
|
||||
|
||||
/* Enable "error correction" */
|
||||
- amvdec_write_dos(core, AV_SCRATCH_F, (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) | BIT(4) | BIT(7));
|
||||
+ amvdec_write_dos(core, AV_SCRATCH_F,
|
||||
+ (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) |
|
||||
+ BIT(4) | BIT(7));
|
||||
|
||||
amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
|
||||
|
||||
@@ -145,7 +141,8 @@ static int codec_h264_stop(struct amvdec_session *sess)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int codec_h264_load_extended_firmware(struct amvdec_session *sess, const u8 *data, u32 len)
|
||||
+static int codec_h264_load_extended_firmware(struct amvdec_session *sess,
|
||||
+ const u8 *data, u32 len)
|
||||
{
|
||||
struct codec_h264 *h264;
|
||||
struct amvdec_core *core = sess->core;
|
||||
@@ -160,7 +157,7 @@ static int codec_h264_load_extended_firmware(struct amvdec_session *sess, const
|
||||
return -EINVAL;
|
||||
|
||||
h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW,
|
||||
- &h264->ext_fw_paddr, GFP_KERNEL);
|
||||
+ &h264->ext_fw_paddr, GFP_KERNEL);
|
||||
if (!h264->ext_fw_vaddr) {
|
||||
dev_err(core->dev, "Failed to alloc H.264 extended fw\n");
|
||||
return -ENOMEM;
|
||||
@@ -275,6 +272,7 @@ static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status)
|
||||
|
||||
amvdec_dst_buf_done_idx(sess, buffer_index, field);
|
||||
|
||||
+ /* 2 src packets per dst frame ; delete additional timestamp */
|
||||
if (field != V4L2_FIELD_NONE && !h264->received_0)
|
||||
amvdec_rm_first_ts(sess);
|
||||
|
||||
diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
index a8d03426e53d0..99dd3ae9c463b 100644
|
||||
--- a/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
+++ b/drivers/media/platform/meson/vdec/vdec_platform.c
|
||||
@@ -154,8 +154,8 @@ static const struct amvdec_format vdec_formats_gxl[] = {
|
||||
.pixfmt = V4L2_PIX_FMT_H264,
|
||||
.min_buffers = 21,
|
||||
.max_buffers = 24,
|
||||
- .max_width = 1920,
|
||||
- .max_height = 1080,
|
||||
+ .max_width = 3840,
|
||||
+ .max_height = 2160,
|
||||
.vdec_ops = &vdec_1_ops,
|
||||
.codec_ops = &codec_h264_ops,
|
||||
.firmware_path = "meson/gxl/vh264_mc",
|
||||
@@ -238,8 +238,8 @@ static const struct amvdec_format vdec_formats_gxm[] = {
|
||||
.pixfmt = V4L2_PIX_FMT_H264,
|
||||
.min_buffers = 21,
|
||||
.max_buffers = 24,
|
||||
- .max_width = 1920,
|
||||
- .max_height = 1080,
|
||||
+ .max_width = 3840,
|
||||
+ .max_height = 2160,
|
||||
.vdec_ops = &vdec_1_ops,
|
||||
.codec_ops = &codec_h264_ops,
|
||||
.firmware_path = "meson/gxm/vh264_mc",
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,81 @@
|
||||
From 6c5aaf27886c9b308e9c4e4d613990e540f23ec8 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 26 Jun 2018 09:37:39 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson-gxbb-nanopi-k2: Add HDMI, CEC and CVBS
|
||||
nodes
|
||||
|
||||
The Amlogic Meson GXBB based Nanopi-K2 board has an HDMI connector
|
||||
with CEC and CVBS available on the 40pin header.
|
||||
This patch adds the nodes to enable HDMI, CEC and CVBS functionnalities.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 48 ++++++++++++++++++++++
|
||||
1 file changed, 48 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
index 7d5709c..cbe99bd 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
@@ -106,6 +106,42 @@
|
||||
compatible = "mmc-pwrseq-emmc";
|
||||
reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
+
|
||||
+ /* CVBS is available on CON1 pin 36, disabled by default */
|
||||
+ cvbs-connector {
|
||||
+ compatible = "composite-video-connector";
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ port {
|
||||
+ cvbs_connector_in: endpoint {
|
||||
+ remote-endpoint = <&cvbs_vdac_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ hdmi-connector {
|
||||
+ compatible = "hdmi-connector";
|
||||
+ type = "a";
|
||||
+
|
||||
+ port {
|
||||
+ hdmi_connector_in: endpoint {
|
||||
+ remote-endpoint = <&hdmi_tx_tmds_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&cec_AO {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&ao_cec_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ hdmi-phandle = <&hdmi_tx>;
|
||||
+};
|
||||
+
|
||||
+&cvbs_vdac_port {
|
||||
+ cvbs_vdac_out: endpoint {
|
||||
+ remote-endpoint = <&cvbs_connector_in>;
|
||||
+ };
|
||||
};
|
||||
|
||||
ðmac {
|
||||
@@ -137,6 +173,18 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&hdmi_tx {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&hdmi_tx_tmds_port {
|
||||
+ hdmi_tx_tmds_out: endpoint {
|
||||
+ remote-endpoint = <&hdmi_connector_in>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
@ -0,0 +1,44 @@
|
||||
From e41c06328d1cd0989899d6a0897c6857d0cf9a4b Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 13 Nov 2017 12:09:40 +0100
|
||||
Subject: [PATCH] ARM64: defconfig: enable CEC support
|
||||
|
||||
Turn on CONFIG_CEC_SUPPORT and CONFIG_CEC_PLATFORM_DRIVERS
|
||||
Turn on CONFIG_VIDEO_MESON_AO_CEC as module
|
||||
Turn on CONFIG_DRM_DW_HDMI_CEC as module
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/configs/defconfig | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
|
||||
index f9a186f..2584605 100644
|
||||
--- a/arch/arm64/configs/defconfig
|
||||
+++ b/arch/arm64/configs/defconfig
|
||||
@@ -402,6 +402,7 @@ CONFIG_MEDIA_SUPPORT=m
|
||||
CONFIG_MEDIA_CAMERA_SUPPORT=y
|
||||
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
|
||||
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
|
||||
+CONFIG_MEDIA_CEC_SUPPORT=y
|
||||
CONFIG_MEDIA_CONTROLLER=y
|
||||
CONFIG_VIDEO_V4L2_SUBDEV_API=y
|
||||
# CONFIG_DVB_NET is not set
|
||||
@@ -411,6 +412,8 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
|
||||
CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
|
||||
CONFIG_VIDEO_RENESAS_FCP=m
|
||||
CONFIG_VIDEO_RENESAS_VSP1=m
|
||||
+CONFIG_CEC_PLATFORM_DRIVERS=y
|
||||
+CONFIG_VIDEO_MESON_AO_CEC=m
|
||||
CONFIG_DRM=m
|
||||
CONFIG_DRM_NOUVEAU=m
|
||||
CONFIG_DRM_EXYNOS=m
|
||||
@@ -431,6 +434,7 @@ CONFIG_DRM_RCAR_LVDS=m
|
||||
CONFIG_DRM_TEGRA=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=m
|
||||
CONFIG_DRM_I2C_ADV7511=m
|
||||
+CONFIG_DRM_DW_HDMI_CEC=m
|
||||
CONFIG_DRM_VC4=m
|
||||
CONFIG_DRM_HISI_HIBMC=m
|
||||
CONFIG_DRM_HISI_KIRIN=m
|
@ -0,0 +1,44 @@
|
||||
From 0cecf963b9d815699fe50b7a7ee4a93ece3ed834 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 19 Jun 2018 18:14:49 +0200
|
||||
Subject: [PATCH] clk: meson: switch gxbb cts-amclk div to the generic divider
|
||||
|
||||
clk-audio-divider was a (poor) attempt to use CCF rate propagation
|
||||
while making sure the PLL rate would be high enough to work with
|
||||
audio use cases. The result is far from optimal. We can do better
|
||||
by carefully choosing the PLL rates for the audio use cases.
|
||||
Doing so, we don't need to use clk-audio-divider anymore. The
|
||||
generic will do
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/meson/gxbb.c | 12 +++++-------
|
||||
1 file changed, 5 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
||||
index 177fffb..69a58cb 100644
|
||||
--- a/drivers/clk/meson/gxbb.c
|
||||
+++ b/drivers/clk/meson/gxbb.c
|
||||
@@ -982,17 +982,15 @@ static struct clk_regmap gxbb_cts_amclk_sel = {
|
||||
};
|
||||
|
||||
static struct clk_regmap gxbb_cts_amclk_div = {
|
||||
- .data = &(struct meson_clk_audio_div_data){
|
||||
- .div = {
|
||||
- .reg_off = HHI_AUD_CLK_CNTL,
|
||||
- .shift = 0,
|
||||
- .width = 8,
|
||||
- },
|
||||
+ .data = &(struct clk_regmap_div_data) {
|
||||
+ .offset = HHI_AUD_CLK_CNTL,
|
||||
+ .shift = 0,
|
||||
+ .width = 8,
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "cts_amclk_div",
|
||||
- .ops = &meson_clk_audio_divider_ops,
|
||||
+ .ops = &clk_regmap_divider_ops,
|
||||
.parent_names = (const char *[]){ "cts_amclk_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
@ -0,0 +1,48 @@
|
||||
From e87dd7b11611e4ac5279ba4ad4f1fea4d0900273 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 19 Jun 2018 18:23:28 +0200
|
||||
Subject: [PATCH] clk: meson: remove unused clk-audio-divider driver
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/meson/Makefile | 2 +-
|
||||
drivers/clk/meson/clkc.h | 7 -------
|
||||
2 files changed, 1 insertion(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
|
||||
index d0d13ae..e40fea9 100644
|
||||
--- a/drivers/clk/meson/Makefile
|
||||
+++ b/drivers/clk/meson/Makefile
|
||||
@@ -2,7 +2,7 @@
|
||||
# Makefile for Meson specific clk
|
||||
#
|
||||
|
||||
-obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o
|
||||
+obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
|
||||
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
|
||||
index 2fb0843..48db024 100644
|
||||
--- a/drivers/clk/meson/clkc.h
|
||||
+++ b/drivers/clk/meson/clkc.h
|
||||
@@ -91,11 +91,6 @@ struct meson_clk_mpll_data {
|
||||
|
||||
#define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
|
||||
|
||||
-struct meson_clk_audio_div_data {
|
||||
- struct parm div;
|
||||
- u8 flags;
|
||||
-};
|
||||
-
|
||||
#define MESON_GATE(_name, _reg, _bit) \
|
||||
struct clk_regmap _name = { \
|
||||
.data = &(struct clk_regmap_gate_data){ \
|
||||
@@ -117,7 +112,5 @@ extern const struct clk_ops meson_clk_pll_ops;
|
||||
extern const struct clk_ops meson_clk_cpu_ops;
|
||||
extern const struct clk_ops meson_clk_mpll_ro_ops;
|
||||
extern const struct clk_ops meson_clk_mpll_ops;
|
||||
-extern const struct clk_ops meson_clk_audio_divider_ro_ops;
|
||||
-extern const struct clk_ops meson_clk_audio_divider_ops;
|
||||
|
||||
#endif /* __CLKC_H */
|
@ -0,0 +1,308 @@
|
||||
From 878d41be386f0bcbe1475f65acd8b9fb304529a0 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 11:49:55 +0200
|
||||
Subject: [PATCH] ASoC: meson: add meson audio core driver
|
||||
|
||||
This patch adds support for the audio core driver for the Amlogic Meson SoC
|
||||
family. The purpose of this driver is to properly reset the audio block and
|
||||
provide register access for the different devices scattered in this address
|
||||
space. This includes output and input DMAs, pcm, i2s and spdif dai, card
|
||||
level routing, internal codec for the gxl variant
|
||||
|
||||
For more information, please refer to the section 5 of the public datasheet
|
||||
of the S905 (gxbb). This datasheet is available here: [0].
|
||||
|
||||
[0]: http://dn.odroid.com/S905/DataSheet/S905_Public_Datasheet_V1.1.4.pdf
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/Kconfig | 1 +
|
||||
sound/soc/Makefile | 1 +
|
||||
sound/soc/meson/Kconfig | 9 ++
|
||||
sound/soc/meson/Makefile | 3 +
|
||||
sound/soc/meson/audio-core.c | 190 +++++++++++++++++++++++++++++++++++++++++++
|
||||
sound/soc/meson/audio-core.h | 28 +++++++
|
||||
6 files changed, 232 insertions(+)
|
||||
create mode 100644 sound/soc/meson/Kconfig
|
||||
create mode 100644 sound/soc/meson/Makefile
|
||||
create mode 100644 sound/soc/meson/audio-core.c
|
||||
create mode 100644 sound/soc/meson/audio-core.h
|
||||
|
||||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
|
||||
index 41af6b9..1cf11cf 100644
|
||||
--- a/sound/soc/Kconfig
|
||||
+++ b/sound/soc/Kconfig
|
||||
@@ -57,6 +57,7 @@ source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/img/Kconfig"
|
||||
source "sound/soc/intel/Kconfig"
|
||||
source "sound/soc/mediatek/Kconfig"
|
||||
+source "sound/soc/meson/Kconfig"
|
||||
source "sound/soc/mxs/Kconfig"
|
||||
source "sound/soc/pxa/Kconfig"
|
||||
source "sound/soc/qcom/Kconfig"
|
||||
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
|
||||
index 06389a5..62a5f87 100644
|
||||
--- a/sound/soc/Makefile
|
||||
+++ b/sound/soc/Makefile
|
||||
@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
|
||||
obj-$(CONFIG_SND_SOC) += img/
|
||||
obj-$(CONFIG_SND_SOC) += intel/
|
||||
obj-$(CONFIG_SND_SOC) += mediatek/
|
||||
+obj-$(CONFIG_SND_SOC) += meson/
|
||||
obj-$(CONFIG_SND_SOC) += mxs/
|
||||
obj-$(CONFIG_SND_SOC) += nuc900/
|
||||
obj-$(CONFIG_SND_SOC) += omap/
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
new file mode 100644
|
||||
index 0000000..ca0e3e9
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -0,0 +1,9 @@
|
||||
+menuconfig SND_SOC_MESON
|
||||
+ tristate "ASoC support for Amlogic Meson SoCs"
|
||||
+ depends on ARCH_MESON
|
||||
+ select MFD_CORE
|
||||
+ select REGMAP_MMIO
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for codecs attached to
|
||||
+ the Amlogic Meson SoCs Audio interfaces. You will also need to
|
||||
+ select the audio interfaces to support below.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
new file mode 100644
|
||||
index 0000000..22028ab
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -0,0 +1,3 @@
|
||||
+snd-soc-meson-audio-core-objs := audio-core.o
|
||||
+
|
||||
+obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
|
||||
diff --git a/sound/soc/meson/audio-core.c b/sound/soc/meson/audio-core.c
|
||||
new file mode 100644
|
||||
index 0000000..99993ec
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/audio-core.c
|
||||
@@ -0,0 +1,190 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/reset.h>
|
||||
+
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-audio-core"
|
||||
+
|
||||
+static const char * const acore_clock_names[] = { "aiu_top",
|
||||
+ "aiu_glue",
|
||||
+ "audin" };
|
||||
+
|
||||
+static int meson_acore_init_clocks(struct device *dev)
|
||||
+{
|
||||
+ struct clk *clock;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(acore_clock_names); i++) {
|
||||
+ clock = devm_clk_get(dev, acore_clock_names[i]);
|
||||
+ if (IS_ERR(clock)) {
|
||||
+ if (PTR_ERR(clock) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Failed to get %s clock\n",
|
||||
+ acore_clock_names[i]);
|
||||
+ return PTR_ERR(clock);
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(clock);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to enable %s clock\n",
|
||||
+ acore_clock_names[i]);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_add_action_or_reset(dev,
|
||||
+ (void(*)(void *))clk_disable_unprepare,
|
||||
+ clock);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const char * const acore_reset_names[] = { "aiu",
|
||||
+ "audin" };
|
||||
+
|
||||
+static int meson_acore_init_resets(struct device *dev)
|
||||
+{
|
||||
+ struct reset_control *reset;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(acore_reset_names); i++) {
|
||||
+ reset = devm_reset_control_get_exclusive(dev,
|
||||
+ acore_reset_names[i]);
|
||||
+ if (IS_ERR(reset)) {
|
||||
+ if (PTR_ERR(reset) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Failed to get %s reset\n",
|
||||
+ acore_reset_names[i]);
|
||||
+ return PTR_ERR(reset);
|
||||
+ }
|
||||
+
|
||||
+ ret = reset_control_reset(reset);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to pulse %s reset\n",
|
||||
+ acore_reset_names[i]);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct regmap_config meson_acore_regmap_config = {
|
||||
+ .reg_bits = 32,
|
||||
+ .val_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+};
|
||||
+
|
||||
+static const struct mfd_cell meson_acore_devs[] = {
|
||||
+ {
|
||||
+ .name = "meson-i2s-dai",
|
||||
+ .of_compatible = "amlogic,meson-i2s-dai",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "meson-spdif-dai",
|
||||
+ .of_compatible = "amlogic,meson-spdif-dai",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "meson-aiu-i2s-dma",
|
||||
+ .of_compatible = "amlogic,meson-aiu-i2s-dma",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "meson-aiu-spdif-dma",
|
||||
+ .of_compatible = "amlogic,meson-aiu-spdif-dma",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int meson_acore_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct meson_audio_core_data *data;
|
||||
+ struct resource *res;
|
||||
+ void __iomem *regs;
|
||||
+ int ret;
|
||||
+
|
||||
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+ platform_set_drvdata(pdev, data);
|
||||
+
|
||||
+ ret = meson_acore_init_clocks(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = meson_acore_init_resets(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aiu");
|
||||
+ regs = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(regs))
|
||||
+ return PTR_ERR(regs);
|
||||
+
|
||||
+ data->aiu = devm_regmap_init_mmio(dev, regs,
|
||||
+ &meson_acore_regmap_config);
|
||||
+ if (IS_ERR(data->aiu)) {
|
||||
+ dev_err(dev, "Couldn't create the AIU regmap\n");
|
||||
+ return PTR_ERR(data->aiu);
|
||||
+ }
|
||||
+
|
||||
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audin");
|
||||
+ regs = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(regs))
|
||||
+ return PTR_ERR(regs);
|
||||
+
|
||||
+ data->audin = devm_regmap_init_mmio(dev, regs,
|
||||
+ &meson_acore_regmap_config);
|
||||
+ if (IS_ERR(data->audin)) {
|
||||
+ dev_err(dev, "Couldn't create the AUDIN regmap\n");
|
||||
+ return PTR_ERR(data->audin);
|
||||
+ }
|
||||
+
|
||||
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, meson_acore_devs,
|
||||
+ ARRAY_SIZE(meson_acore_devs), NULL, 0,
|
||||
+ NULL);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id meson_acore_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-audio-core", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-audio-core", },
|
||||
+ { .compatible = "amlogic,meson-gxl-audio-core", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, meson_acore_of_match);
|
||||
+
|
||||
+static struct platform_driver meson_acore_pdrv = {
|
||||
+ .probe = meson_acore_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = meson_acore_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_acore_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson Audio Core Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
diff --git a/sound/soc/meson/audio-core.h b/sound/soc/meson/audio-core.h
|
||||
new file mode 100644
|
||||
index 0000000..6e7a24c
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/audio-core.h
|
||||
@@ -0,0 +1,28 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _MESON_AUDIO_CORE_H_
|
||||
+#define _MESON_AUDIO_CORE_H_
|
||||
+
|
||||
+struct meson_audio_core_data {
|
||||
+ struct regmap *aiu;
|
||||
+ struct regmap *audin;
|
||||
+};
|
||||
+
|
||||
+#endif /* _MESON_AUDIO_CORE_H_ */
|
@ -0,0 +1,357 @@
|
||||
From f6c0ce626b08f5ba85bd9bfe000044c4f9e7da24 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:00:10 +0200
|
||||
Subject: [PATCH] ASoC: meson: add register definitions
|
||||
|
||||
Add the register definition for the AIU and AUDIN blocks
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/aiu-regs.h | 182 +++++++++++++++++++++++++++++++++++++++++++
|
||||
sound/soc/meson/audin-regs.h | 148 +++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 330 insertions(+)
|
||||
create mode 100644 sound/soc/meson/aiu-regs.h
|
||||
create mode 100644 sound/soc/meson/audin-regs.h
|
||||
|
||||
diff --git a/sound/soc/meson/aiu-regs.h b/sound/soc/meson/aiu-regs.h
|
||||
new file mode 100644
|
||||
index 0000000..67391e6
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-regs.h
|
||||
@@ -0,0 +1,182 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _AIU_REGS_H_
|
||||
+#define _AIU_REGS_H_
|
||||
+
|
||||
+#define AIU_958_BPF 0x000
|
||||
+#define AIU_958_BRST 0x004
|
||||
+#define AIU_958_LENGTH 0x008
|
||||
+#define AIU_958_PADDSIZE 0x00C
|
||||
+#define AIU_958_MISC 0x010
|
||||
+#define AIU_958_FORCE_LEFT 0x014 /* Unknown */
|
||||
+#define AIU_958_DISCARD_NUM 0x018
|
||||
+#define AIU_958_DCU_FF_CTRL 0x01C
|
||||
+#define AIU_958_CHSTAT_L0 0x020
|
||||
+#define AIU_958_CHSTAT_L1 0x024
|
||||
+#define AIU_958_CTRL 0x028
|
||||
+#define AIU_958_RPT 0x02C
|
||||
+#define AIU_I2S_MUTE_SWAP 0x030
|
||||
+#define AIU_I2S_SOURCE_DESC 0x034
|
||||
+#define AIU_I2S_MED_CTRL 0x038
|
||||
+#define AIU_I2S_MED_THRESH 0x03C
|
||||
+#define AIU_I2S_DAC_CFG 0x040
|
||||
+#define AIU_I2S_SYNC 0x044 /* Unknown */
|
||||
+#define AIU_I2S_MISC 0x048
|
||||
+#define AIU_I2S_OUT_CFG 0x04C
|
||||
+#define AIU_I2S_FF_CTRL 0x050 /* Unknown */
|
||||
+#define AIU_RST_SOFT 0x054
|
||||
+#define AIU_CLK_CTRL 0x058
|
||||
+#define AIU_MIX_ADCCFG 0x05C
|
||||
+#define AIU_MIX_CTRL 0x060
|
||||
+#define AIU_CLK_CTRL_MORE 0x064
|
||||
+#define AIU_958_POP 0x068
|
||||
+#define AIU_MIX_GAIN 0x06C
|
||||
+#define AIU_958_SYNWORD1 0x070
|
||||
+#define AIU_958_SYNWORD2 0x074
|
||||
+#define AIU_958_SYNWORD3 0x078
|
||||
+#define AIU_958_SYNWORD1_MASK 0x07C
|
||||
+#define AIU_958_SYNWORD2_MASK 0x080
|
||||
+#define AIU_958_SYNWORD3_MASK 0x084
|
||||
+#define AIU_958_FFRDOUT_THD 0x088
|
||||
+#define AIU_958_LENGTH_PER_PAUSE 0x08C
|
||||
+#define AIU_958_PAUSE_NUM 0x090
|
||||
+#define AIU_958_PAUSE_PAYLOAD 0x094
|
||||
+#define AIU_958_AUTO_PAUSE 0x098
|
||||
+#define AIU_958_PAUSE_PD_LENGTH 0x09C
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL 0x0A0
|
||||
+#define AIU_CODEC_ADC_LRCLK_CTRL 0x0A4
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL 0x0A8
|
||||
+#define AIU_CODEC_CLK_DATA_CTRL 0x0AC
|
||||
+#define AIU_ACODEC_CTRL 0x0B0
|
||||
+#define AIU_958_CHSTAT_R0 0x0C0
|
||||
+#define AIU_958_CHSTAT_R1 0x0C4
|
||||
+#define AIU_958_VALID_CTRL 0x0C8
|
||||
+#define AIU_AUDIO_AMP_REG0 0x0F0 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG1 0x0F4 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG2 0x0F8 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG3 0x0FC /* Unknown */
|
||||
+#define AIU_AIFIFO2_CTRL 0x100
|
||||
+#define AIU_AIFIFO2_STATUS 0x104
|
||||
+#define AIU_AIFIFO2_GBIT 0x108
|
||||
+#define AIU_AIFIFO2_CLB 0x10C
|
||||
+#define AIU_CRC_CTRL 0x110
|
||||
+#define AIU_CRC_STATUS 0x114
|
||||
+#define AIU_CRC_SHIFT_REG 0x118
|
||||
+#define AIU_CRC_IREG 0x11C
|
||||
+#define AIU_CRC_CAL_REG1 0x120
|
||||
+#define AIU_CRC_CAL_REG0 0x124
|
||||
+#define AIU_CRC_POLY_COEF1 0x128
|
||||
+#define AIU_CRC_POLY_COEF0 0x12C
|
||||
+#define AIU_CRC_BIT_SIZE1 0x130
|
||||
+#define AIU_CRC_BIT_SIZE0 0x134
|
||||
+#define AIU_CRC_BIT_CNT1 0x138
|
||||
+#define AIU_CRC_BIT_CNT0 0x13C
|
||||
+#define AIU_AMCLK_GATE_HI 0x140
|
||||
+#define AIU_AMCLK_GATE_LO 0x144
|
||||
+#define AIU_AMCLK_MSR 0x148
|
||||
+#define AIU_AUDAC_CTRL0 0x14C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA0 0x154 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA1 0x158 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA2 0x15C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA3 0x160 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA4 0x164 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA5 0x168 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA6 0x16C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA7 0x170 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA_LCNTS 0x174 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA_RCNTS 0x178 /* Unknown */
|
||||
+#define AIU_MEM_I2S_START_PTR 0x180
|
||||
+#define AIU_MEM_I2S_RD_PTR 0x184
|
||||
+#define AIU_MEM_I2S_END_PTR 0x188
|
||||
+#define AIU_MEM_I2S_MASKS 0x18C
|
||||
+#define AIU_MEM_I2S_CONTROL 0x190
|
||||
+#define AIU_MEM_IEC958_START_PTR 0x194
|
||||
+#define AIU_MEM_IEC958_RD_PTR 0x198
|
||||
+#define AIU_MEM_IEC958_END_PTR 0x19C
|
||||
+#define AIU_MEM_IEC958_MASKS 0x1A0
|
||||
+#define AIU_MEM_IEC958_CONTROL 0x1A4
|
||||
+#define AIU_MEM_AIFIFO2_START_PTR 0x1A8
|
||||
+#define AIU_MEM_AIFIFO2_CURR_PTR 0x1AC
|
||||
+#define AIU_MEM_AIFIFO2_END_PTR 0x1B0
|
||||
+#define AIU_MEM_AIFIFO2_BYTES_AVAIL 0x1B4
|
||||
+#define AIU_MEM_AIFIFO2_CONTROL 0x1B8
|
||||
+#define AIU_MEM_AIFIFO2_MAN_WP 0x1BC
|
||||
+#define AIU_MEM_AIFIFO2_MAN_RP 0x1C0
|
||||
+#define AIU_MEM_AIFIFO2_LEVEL 0x1C4
|
||||
+#define AIU_MEM_AIFIFO2_BUF_CNTL 0x1C8
|
||||
+#define AIU_MEM_I2S_MAN_WP 0x1CC
|
||||
+#define AIU_MEM_I2S_MAN_RP 0x1D0
|
||||
+#define AIU_MEM_I2S_LEVEL 0x1D4
|
||||
+#define AIU_MEM_I2S_BUF_CNTL 0x1D8
|
||||
+#define AIU_MEM_I2S_BUF_WRAP_COUNT 0x1DC
|
||||
+#define AIU_MEM_I2S_MEM_CTL 0x1E0
|
||||
+#define AIU_MEM_IEC958_MEM_CTL 0x1E4
|
||||
+#define AIU_MEM_IEC958_WRAP_COUNT 0x1E8
|
||||
+#define AIU_MEM_IEC958_IRQ_LEVEL 0x1EC
|
||||
+#define AIU_MEM_IEC958_MAN_WP 0x1F0
|
||||
+#define AIU_MEM_IEC958_MAN_RP 0x1F4
|
||||
+#define AIU_MEM_IEC958_LEVEL 0x1F8
|
||||
+#define AIU_MEM_IEC958_BUF_CNTL 0x1FC
|
||||
+#define AIU_AIFIFO_CTRL 0x200
|
||||
+#define AIU_AIFIFO_STATUS 0x204
|
||||
+#define AIU_AIFIFO_GBIT 0x208
|
||||
+#define AIU_AIFIFO_CLB 0x20C
|
||||
+#define AIU_MEM_AIFIFO_START_PTR 0x210
|
||||
+#define AIU_MEM_AIFIFO_CURR_PTR 0x214
|
||||
+#define AIU_MEM_AIFIFO_END_PTR 0x218
|
||||
+#define AIU_MEM_AIFIFO_BYTES_AVAIL 0x21C
|
||||
+#define AIU_MEM_AIFIFO_CONTROL 0x220
|
||||
+#define AIU_MEM_AIFIFO_MAN_WP 0x224
|
||||
+#define AIU_MEM_AIFIFO_MAN_RP 0x228
|
||||
+#define AIU_MEM_AIFIFO_LEVEL 0x22C
|
||||
+#define AIU_MEM_AIFIFO_BUF_CNTL 0x230
|
||||
+#define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x234
|
||||
+#define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x238
|
||||
+#define AIU_MEM_AIFIFO_MEM_CTL 0x23C
|
||||
+#define AIFIFO_TIME_STAMP_CNTL 0x240
|
||||
+#define AIFIFO_TIME_STAMP_SYNC_0 0x244
|
||||
+#define AIFIFO_TIME_STAMP_SYNC_1 0x248
|
||||
+#define AIFIFO_TIME_STAMP_0 0x24C
|
||||
+#define AIFIFO_TIME_STAMP_1 0x250
|
||||
+#define AIFIFO_TIME_STAMP_2 0x254
|
||||
+#define AIFIFO_TIME_STAMP_3 0x258
|
||||
+#define AIFIFO_TIME_STAMP_LENGTH 0x25C
|
||||
+#define AIFIFO2_TIME_STAMP_CNTL 0x260
|
||||
+#define AIFIFO2_TIME_STAMP_SYNC_0 0x264
|
||||
+#define AIFIFO2_TIME_STAMP_SYNC_1 0x268
|
||||
+#define AIFIFO2_TIME_STAMP_0 0x26C
|
||||
+#define AIFIFO2_TIME_STAMP_1 0x270
|
||||
+#define AIFIFO2_TIME_STAMP_2 0x274
|
||||
+#define AIFIFO2_TIME_STAMP_3 0x278
|
||||
+#define AIFIFO2_TIME_STAMP_LENGTH 0x27C
|
||||
+#define IEC958_TIME_STAMP_CNTL 0x280
|
||||
+#define IEC958_TIME_STAMP_SYNC_0 0x284
|
||||
+#define IEC958_TIME_STAMP_SYNC_1 0x288
|
||||
+#define IEC958_TIME_STAMP_0 0x28C
|
||||
+#define IEC958_TIME_STAMP_1 0x290
|
||||
+#define IEC958_TIME_STAMP_2 0x294
|
||||
+#define IEC958_TIME_STAMP_3 0x298
|
||||
+#define IEC958_TIME_STAMP_LENGTH 0x29C
|
||||
+#define AIU_MEM_AIFIFO2_MEM_CTL 0x2A0
|
||||
+#define AIU_I2S_CBUS_DDR_CNTL 0x2A4
|
||||
+#define AIU_I2S_CBUS_DDR_WDATA 0x2A8
|
||||
+#define AIU_I2S_CBUS_DDR_ADDR 0x2AC
|
||||
+
|
||||
+#endif /* _AIU_REGS_H_ */
|
||||
diff --git a/sound/soc/meson/audin-regs.h b/sound/soc/meson/audin-regs.h
|
||||
new file mode 100644
|
||||
index 0000000..f224610
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/audin-regs.h
|
||||
@@ -0,0 +1,148 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _AUDIN_REGS_H_
|
||||
+#define _AUDIN_REGS_H_
|
||||
+
|
||||
+/*
|
||||
+ * Note :
|
||||
+ * Datasheet issue page 196
|
||||
+ * AUDIN_MUTE_VAL 0x35 => impossible: Already assigned to AUDIN_FIFO1_PTR
|
||||
+ * AUDIN_FIFO1_PTR is more likely to be correct here since surrounding registers
|
||||
+ * also deal with AUDIN_FIFO1
|
||||
+ *
|
||||
+ * Clarification needed from Amlogic
|
||||
+ */
|
||||
+
|
||||
+#define AUDIN_SPDIF_MODE 0x000
|
||||
+#define AUDIN_SPDIF_FS_CLK_RLTN 0x004
|
||||
+#define AUDIN_SPDIF_CHNL_STS_A 0x008
|
||||
+#define AUDIN_SPDIF_CHNL_STS_B 0x00C
|
||||
+#define AUDIN_SPDIF_MISC 0x010
|
||||
+#define AUDIN_SPDIF_NPCM_PCPD 0x014
|
||||
+#define AUDIN_SPDIF_END 0x03C /* Unknown */
|
||||
+#define AUDIN_I2SIN_CTRL 0x040
|
||||
+#define AUDIN_SOURCE_SEL 0x044
|
||||
+#define AUDIN_DECODE_FORMAT 0x048
|
||||
+#define AUDIN_DECODE_CONTROL_STATUS 0x04C
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_0 0x050
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_1 0x054
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_2 0x058
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_3 0x05C
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_4 0x060
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_5 0x064
|
||||
+#define AUDIN_FIFO0_START 0x080
|
||||
+#define AUDIN_FIFO0_END 0x084
|
||||
+#define AUDIN_FIFO0_PTR 0x088
|
||||
+#define AUDIN_FIFO0_INTR 0x08C
|
||||
+#define AUDIN_FIFO0_RDPTR 0x090
|
||||
+#define AUDIN_FIFO0_CTRL 0x094
|
||||
+#define AUDIN_FIFO0_CTRL1 0x098
|
||||
+#define AUDIN_FIFO0_LVL0 0x09C
|
||||
+#define AUDIN_FIFO0_LVL1 0x0A0
|
||||
+#define AUDIN_FIFO0_LVL2 0x0A4
|
||||
+#define AUDIN_FIFO0_REQID 0x0C0
|
||||
+#define AUDIN_FIFO0_WRAP 0x0C4
|
||||
+#define AUDIN_FIFO1_START 0x0CC
|
||||
+#define AUDIN_FIFO1_END 0x0D0
|
||||
+#define AUDIN_FIFO1_PTR 0x0D4
|
||||
+#define AUDIN_FIFO1_INTR 0x0D8
|
||||
+#define AUDIN_FIFO1_RDPTR 0x0DC
|
||||
+#define AUDIN_FIFO1_CTRL 0x0E0
|
||||
+#define AUDIN_FIFO1_CTRL1 0x0E4
|
||||
+#define AUDIN_FIFO1_LVL0 0x100
|
||||
+#define AUDIN_FIFO1_LVL1 0x104
|
||||
+#define AUDIN_FIFO1_LVL2 0x108
|
||||
+#define AUDIN_FIFO1_REQID 0x10C
|
||||
+#define AUDIN_FIFO1_WRAP 0x110
|
||||
+#define AUDIN_FIFO2_START 0x114
|
||||
+#define AUDIN_FIFO2_END 0x118
|
||||
+#define AUDIN_FIFO2_PTR 0x11C
|
||||
+#define AUDIN_FIFO2_INTR 0x120
|
||||
+#define AUDIN_FIFO2_RDPTR 0x124
|
||||
+#define AUDIN_FIFO2_CTRL 0x128
|
||||
+#define AUDIN_FIFO2_CTRL1 0x12C
|
||||
+#define AUDIN_FIFO2_LVL0 0x130
|
||||
+#define AUDIN_FIFO2_LVL1 0x134
|
||||
+#define AUDIN_FIFO2_LVL2 0x138
|
||||
+#define AUDIN_FIFO2_REQID 0x13C
|
||||
+#define AUDIN_FIFO2_WRAP 0x140
|
||||
+#define AUDIN_INT_CTRL 0x144
|
||||
+#define AUDIN_FIFO_INT 0x148
|
||||
+#define PCMIN_CTRL0 0x180
|
||||
+#define PCMIN_CTRL1 0x184
|
||||
+#define PCMIN1_CTRL0 0x188
|
||||
+#define PCMIN1_CTRL1 0x18C
|
||||
+#define PCMOUT_CTRL0 0x1C0
|
||||
+#define PCMOUT_CTRL1 0x1C4
|
||||
+#define PCMOUT_CTRL2 0x1C8
|
||||
+#define PCMOUT_CTRL3 0x1CC
|
||||
+#define PCMOUT1_CTRL0 0x1D0
|
||||
+#define PCMOUT1_CTRL1 0x1D4
|
||||
+#define PCMOUT1_CTRL2 0x1D8
|
||||
+#define PCMOUT1_CTRL3 0x1DC
|
||||
+#define AUDOUT_CTRL 0x200
|
||||
+#define AUDOUT_CTRL1 0x204
|
||||
+#define AUDOUT_BUF0_STA 0x208
|
||||
+#define AUDOUT_BUF0_EDA 0x20C
|
||||
+#define AUDOUT_BUF0_WPTR 0x210
|
||||
+#define AUDOUT_BUF1_STA 0x214
|
||||
+#define AUDOUT_BUF1_EDA 0x218
|
||||
+#define AUDOUT_BUF1_WPTR 0x21C
|
||||
+#define AUDOUT_FIFO_RPTR 0x220
|
||||
+#define AUDOUT_INTR_PTR 0x224
|
||||
+#define AUDOUT_FIFO_STS 0x228
|
||||
+#define AUDOUT1_CTRL 0x240
|
||||
+#define AUDOUT1_CTRL1 0x244
|
||||
+#define AUDOUT1_BUF0_STA 0x248
|
||||
+#define AUDOUT1_BUF0_EDA 0x24C
|
||||
+#define AUDOUT1_BUF0_WPTR 0x250
|
||||
+#define AUDOUT1_BUF1_STA 0x254
|
||||
+#define AUDOUT1_BUF1_EDA 0x258
|
||||
+#define AUDOUT1_BUF1_WPTR 0x25C
|
||||
+#define AUDOUT1_FIFO_RPTR 0x260
|
||||
+#define AUDOUT1_INTR_PTR 0x264
|
||||
+#define AUDOUT1_FIFO_STS 0x268
|
||||
+#define AUDIN_HDMI_MEAS_CTRL 0x280
|
||||
+#define AUDIN_HDMI_MEAS_CYCLES_M1 0x284
|
||||
+#define AUDIN_HDMI_MEAS_INTR_MASKN 0x288
|
||||
+#define AUDIN_HDMI_MEAS_INTR_STAT 0x28C
|
||||
+#define AUDIN_HDMI_REF_CYCLES_STAT_0 0x290
|
||||
+#define AUDIN_HDMI_REF_CYCLES_STAT_1 0x294
|
||||
+#define AUDIN_HDMIRX_AFIFO_STAT 0x298
|
||||
+#define AUDIN_FIFO0_PIO_STS 0x2C0
|
||||
+#define AUDIN_FIFO0_PIO_RDL 0x2C4
|
||||
+#define AUDIN_FIFO0_PIO_RDH 0x2C8
|
||||
+#define AUDIN_FIFO1_PIO_STS 0x2CC
|
||||
+#define AUDIN_FIFO1_PIO_RDL 0x2D0
|
||||
+#define AUDIN_FIFO1_PIO_RDH 0x2D4
|
||||
+#define AUDIN_FIFO2_PIO_STS 0x2D8
|
||||
+#define AUDIN_FIFO2_PIO_RDL 0x2DC
|
||||
+#define AUDIN_FIFO2_PIO_RDH 0x2E0
|
||||
+#define AUDOUT_FIFO_PIO_STS 0x2E4
|
||||
+#define AUDOUT_FIFO_PIO_WRL 0x2E8
|
||||
+#define AUDOUT_FIFO_PIO_WRH 0x2EC
|
||||
+#define AUDOUT1_FIFO_PIO_STS 0x2F0 /* Unknown */
|
||||
+#define AUDOUT1_FIFO_PIO_WRL 0x2F4 /* Unknown */
|
||||
+#define AUDOUT1_FIFO_PIO_WRH 0x2F8 /* Unknown */
|
||||
+#define AUD_RESAMPLE_CTRL0 0x2FC
|
||||
+#define AUD_RESAMPLE_CTRL1 0x300
|
||||
+#define AUD_RESAMPLE_STATUS 0x304
|
||||
+
|
||||
+#endif /* _AUDIN_REGS_H_ */
|
@ -0,0 +1,416 @@
|
||||
From bb5102086db1579c1289440fa8aa184a70cb7c64 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:14:40 +0200
|
||||
Subject: [PATCH] ASoC: meson: add aiu i2s dma support
|
||||
|
||||
Add support for the i2s output dma which is part of the AIU block
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 7 +
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/aiu-i2s-dma.c | 370 ++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 379 insertions(+)
|
||||
create mode 100644 sound/soc/meson/aiu-i2s-dma.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index ca0e3e9..88fbfc2 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -7,3 +7,10 @@ menuconfig SND_SOC_MESON
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the Amlogic Meson SoCs Audio interfaces. You will also need to
|
||||
select the audio interfaces to support below.
|
||||
+
|
||||
+config SND_SOC_MESON_I2S
|
||||
+ tristate "Meson i2s interface"
|
||||
+ depends on SND_SOC_MESON
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for i2s dma driver for Amlogic
|
||||
+ Meson SoCs.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index 22028ab..273f275 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -1,3 +1,5 @@
|
||||
snd-soc-meson-audio-core-objs := audio-core.o
|
||||
+snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
|
||||
+obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
|
||||
diff --git a/sound/soc/meson/aiu-i2s-dma.c b/sound/soc/meson/aiu-i2s-dma.c
|
||||
new file mode 100644
|
||||
index 0000000..2684bd0
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-i2s-dma.c
|
||||
@@ -0,0 +1,370 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-aiu-i2s-dma"
|
||||
+
|
||||
+struct aiu_i2s_dma {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *fast;
|
||||
+ int irq;
|
||||
+};
|
||||
+
|
||||
+#define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0)
|
||||
+#define AIU_MEM_I2S_CONTROL_INIT BIT(0)
|
||||
+#define AIU_MEM_I2S_CONTROL_FILL_EN BIT(1)
|
||||
+#define AIU_MEM_I2S_CONTROL_EMPTY_EN BIT(2)
|
||||
+#define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6)
|
||||
+#define AIU_MEM_I2S_CONTROL_BUSY BIT(7)
|
||||
+#define AIU_MEM_I2S_CONTROL_DATA_READY BIT(8)
|
||||
+#define AIU_MEM_I2S_CONTROL_LEVEL_CNTL BIT(9)
|
||||
+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK_MASK GENMASK(31, 16)
|
||||
+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK(n) ((n) << 16)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_MEM_MASK GENMASK(15, 8)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_MEM(ch) ((ch) << 8)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_RD_MASK GENMASK(7, 0)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_RD(ch) ((ch) << 0)
|
||||
+#define AIU_RST_SOFT_I2S_FAST_DOMAIN BIT(0)
|
||||
+#define AIU_RST_SOFT_I2S_SLOW_DOMAIN BIT(1)
|
||||
+
|
||||
+/*
|
||||
+ * The DMA works by i2s "blocks" (or DMA burst). The burst size and the memory
|
||||
+ * layout expected depends on the mode of operation.
|
||||
+ *
|
||||
+ * - Normal mode: The channels are expected to be packed in 32 bytes groups
|
||||
+ * interleaved the buffer. AIU_MEM_I2S_MASKS_CH_MEM is a bitfield representing
|
||||
+ * the channels present in memory. AIU_MEM_I2S_MASKS_CH_MEM represents the
|
||||
+ * channels read by the DMA. This is very flexible but the unsual memory layout
|
||||
+ * makes it less easy to deal with. The burst size is 32 bytes times the number
|
||||
+ * of channels read.
|
||||
+ *
|
||||
+ * - Split mode:
|
||||
+ * Classical channel interleaved frame organisation. In this mode,
|
||||
+ * AIU_MEM_I2S_MASKS_CH_MEM and AIU_MEM_I2S_MASKS_CH_MEM must be set to 0xff and
|
||||
+ * the burst size is fixed to 256 bytes. The input can be either 2 or 8
|
||||
+ * channels.
|
||||
+ *
|
||||
+ * The following driver implements the split mode.
|
||||
+ */
|
||||
+
|
||||
+#define AIU_I2S_DMA_BURST 256
|
||||
+
|
||||
+static struct snd_pcm_hardware aiu_i2s_dma_hw = {
|
||||
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID |
|
||||
+ SNDRV_PCM_INFO_PAUSE),
|
||||
+
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE),
|
||||
+
|
||||
+ /*
|
||||
+ * TODO: The DMA can change the endianness, the msb position
|
||||
+ * and deal with unsigned - support this later on
|
||||
+ */
|
||||
+
|
||||
+ .rate_min = 8000,
|
||||
+ .rate_max = 192000,
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 8,
|
||||
+ .period_bytes_min = AIU_I2S_DMA_BURST,
|
||||
+ .period_bytes_max = AIU_I2S_DMA_BURST * 65535,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = UINT_MAX,
|
||||
+ .buffer_bytes_max = 1 * 1024 * 1024,
|
||||
+ .fifo_size = 0,
|
||||
+};
|
||||
+
|
||||
+static struct aiu_i2s_dma *aiu_i2s_dma_priv(struct snd_pcm_substream *s)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = s->private_data;
|
||||
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
+
|
||||
+ return snd_soc_component_get_drvdata(component);
|
||||
+}
|
||||
+
|
||||
+static snd_pcm_uframes_t
|
||||
+aiu_i2s_dma_pointer(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ unsigned int addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR,
|
||||
+ &addr);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
|
||||
+}
|
||||
+
|
||||
+static void __dma_enable(struct aiu_i2s_dma *priv, bool enable)
|
||||
+{
|
||||
+ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN |
|
||||
+ AIU_MEM_I2S_CONTROL_EMPTY_EN);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask,
|
||||
+ enable ? en_mask : 0);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __dma_enable(priv, true);
|
||||
+ break;
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ __dma_enable(priv, false);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __dma_init_mem(struct aiu_i2s_dma *priv)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT,
|
||||
+ 0);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT,
|
||||
+ 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ __dma_init_mem(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ int ret;
|
||||
+ u32 burst_num, mem_ctl;
|
||||
+ dma_addr_t end_ptr;
|
||||
+
|
||||
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Setup memory layout */
|
||||
+ if (params_physical_width(params) == 16)
|
||||
+ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT;
|
||||
+ else
|
||||
+ mem_ctl = 0;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_MODE_16BIT,
|
||||
+ mem_ctl);
|
||||
+
|
||||
+ /* Initialize memory pointers */
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_START_PTR, runtime->dma_addr);
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_RD_PTR, runtime->dma_addr);
|
||||
+
|
||||
+ /* The end pointer is the address of the last valid block */
|
||||
+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_I2S_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_END_PTR, end_ptr);
|
||||
+
|
||||
+ /* Memory masks */
|
||||
+ burst_num = params_period_bytes(params) / AIU_I2S_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_MASKS,
|
||||
+ AIU_MEM_I2S_MASKS_CH_RD(0xff) |
|
||||
+ AIU_MEM_I2S_MASKS_CH_MEM(0xff) |
|
||||
+ AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ return snd_pcm_lib_free_pages(substream);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static irqreturn_t aiu_i2s_dma_irq_block(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct snd_pcm_substream *playback = dev_id;
|
||||
+
|
||||
+ snd_pcm_period_elapsed(playback);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ int ret;
|
||||
+
|
||||
+ snd_soc_set_runtime_hwparams(substream, &aiu_i2s_dma_hw);
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the buffer and period size are multiple of the DMA burst
|
||||
+ * size
|
||||
+ */
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
+ AIU_I2S_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
||||
+ AIU_I2S_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Request the I2S DDR irq */
|
||||
+ ret = request_irq(priv->irq, aiu_i2s_dma_irq_block, 0,
|
||||
+ DRV_NAME, substream);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Power up the i2s fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Make sure the dma is initially disabled */
|
||||
+ __dma_enable(priv, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+ free_irq(priv->irq, substream);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_pcm_ops aiu_i2s_dma_ops = {
|
||||
+ .open = aiu_i2s_dma_open,
|
||||
+ .close = aiu_i2s_dma_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = aiu_i2s_dma_hw_params,
|
||||
+ .hw_free = aiu_i2s_dma_hw_free,
|
||||
+ .prepare = aiu_i2s_dma_prepare,
|
||||
+ .pointer = aiu_i2s_dma_pointer,
|
||||
+ .trigger = aiu_i2s_dma_trigger,
|
||||
+};
|
||||
+
|
||||
+static int aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_card *card = rtd->card->snd_card;
|
||||
+ size_t size = aiu_i2s_dma_hw.buffer_bytes_max;
|
||||
+
|
||||
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
+ SNDRV_DMA_TYPE_DEV,
|
||||
+ card->dev, size, size);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver aiu_i2s_platform = {
|
||||
+ .ops = &aiu_i2s_dma_ops,
|
||||
+ .pcm_new = aiu_i2s_dma_new,
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int aiu_i2s_dma_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct aiu_i2s_dma *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get i2s fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->irq = platform_get_irq(pdev, 0);
|
||||
+ if (priv->irq <= 0) {
|
||||
+ dev_err(dev, "Can't get i2s ddr irq\n");
|
||||
+ return priv->irq;
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &aiu_i2s_platform,
|
||||
+ NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id aiu_i2s_dma_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-aiu-i2s-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-aiu-i2s-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxl-aiu-i2s-dma", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, aiu_i2s_dma_of_match);
|
||||
+
|
||||
+static struct platform_driver aiu_i2s_dma_pdrv = {
|
||||
+ .probe = aiu_i2s_dma_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = aiu_i2s_dma_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(aiu_i2s_dma_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson AIU i2s DMA ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,511 @@
|
||||
From 6a5036e9f7dbd99023c6f9482fed3a747868b1c2 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:17:27 +0200
|
||||
Subject: [PATCH] ASoC: meson: add initial i2s dai support
|
||||
|
||||
Add support for the i2s dai found on Amlogic Meson SoC family.
|
||||
With this initial implementation, only playback is supported.
|
||||
Capture will be part of furture work.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 2 +-
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/i2s-dai.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 468 insertions(+), 1 deletion(-)
|
||||
create mode 100644 sound/soc/meson/i2s-dai.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 88fbfc2..478f29a 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -12,5 +12,5 @@ config SND_SOC_MESON_I2S
|
||||
tristate "Meson i2s interface"
|
||||
depends on SND_SOC_MESON
|
||||
help
|
||||
- Say Y or M if you want to add support for i2s dma driver for Amlogic
|
||||
+ Say Y or M if you want to add support for i2s driver for Amlogic
|
||||
Meson SoCs.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index 273f275..ea06dde 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -1,5 +1,7 @@
|
||||
snd-soc-meson-audio-core-objs := audio-core.o
|
||||
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
|
||||
+snd-soc-meson-i2s-dai-objs := i2s-dai.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
|
||||
+obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
|
||||
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
|
||||
new file mode 100644
|
||||
index 0000000..1008af8
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -0,0 +1,465 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-i2s-dai"
|
||||
+
|
||||
+struct meson_i2s_dai {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *mclk;
|
||||
+ struct clk *bclks;
|
||||
+ struct clk *iface;
|
||||
+ struct clk *fast;
|
||||
+ bool bclks_idle;
|
||||
+};
|
||||
+
|
||||
+#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0)
|
||||
+#define AIU_CLK_CTRL_I2S_DIV_MASK GENMASK(3, 2)
|
||||
+#define AIU_CLK_CTRL_AOCLK_POLARITY_MASK BIT(6)
|
||||
+#define AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL (0 << 6)
|
||||
+#define AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED (1 << 6)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_POLARITY_MASK BIT(7)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL (0 << 7)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED (1 << 7)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_SKEW_MASK GENMASK(9, 8)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_LEFT_J (0 << 8)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_I2S (1 << 8)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8)
|
||||
+#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0)
|
||||
+#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0)
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0)
|
||||
+#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0)
|
||||
+#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0)
|
||||
+#define AIU_I2S_DAC_CFG_AOCLK_64 (3 << 0)
|
||||
+#define AIU_I2S_MISC_HOLD_EN BIT(2)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
|
||||
+
|
||||
+static void __hold(struct meson_i2s_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_MISC,
|
||||
+ AIU_I2S_MISC_HOLD_EN,
|
||||
+ enable ? AIU_I2S_MISC_HOLD_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __divider_enable(struct meson_i2s_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_I2S_DIV_EN,
|
||||
+ enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __playback_start(struct meson_i2s_dai *priv)
|
||||
+{
|
||||
+ __divider_enable(priv, true);
|
||||
+ __hold(priv, false);
|
||||
+}
|
||||
+
|
||||
+static void __playback_stop(struct meson_i2s_dai *priv, bool clk_force)
|
||||
+{
|
||||
+ __hold(priv, true);
|
||||
+ /* Disable the bit clks if necessary */
|
||||
+ if (clk_force || !priv->bclks_idle)
|
||||
+ __divider_enable(priv, false);
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ bool clk_force_stop = false;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __playback_start(priv);
|
||||
+ return 0;
|
||||
+
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ clk_force_stop = true;
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ __playback_stop(priv, clk_force_stop);
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int __bclks_set_rate(struct meson_i2s_dai *priv, unsigned int srate,
|
||||
+ unsigned int width)
|
||||
+{
|
||||
+ unsigned int fs;
|
||||
+
|
||||
+ /* Get the oversampling factor */
|
||||
+ fs = DIV_ROUND_CLOSEST(clk_get_rate(priv->mclk), srate);
|
||||
+
|
||||
+ /*
|
||||
+ * This DAI is usually connected to the dw-hdmi which does not support
|
||||
+ * bclk being 32 * lrclk or 48 * lrclk
|
||||
+ * Restrict to blck = 64 * lrclk
|
||||
+ */
|
||||
+ if (fs % 64)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* Set the divider between lrclk and bclk */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_DAC_CFG,
|
||||
+ AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK,
|
||||
+ AIU_I2S_DAC_CFG_AOCLK_64);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CODEC_DAC_LRCLK_CTRL,
|
||||
+ AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK,
|
||||
+ AIU_CODEC_DAC_LRCLK_CTRL_DIV(64));
|
||||
+
|
||||
+ /* Use CLK_MORE for the i2s divider */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_I2S_DIV_MASK,
|
||||
+ 0);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE,
|
||||
+ AIU_CLK_CTRL_MORE_I2S_DIV_MASK,
|
||||
+ AIU_CLK_CTRL_MORE_I2S_DIV(fs / 64));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __setup_desc(struct meson_i2s_dai *priv, unsigned int width,
|
||||
+ unsigned int channels)
|
||||
+{
|
||||
+ u32 desc = 0;
|
||||
+
|
||||
+ switch (width) {
|
||||
+ case 24:
|
||||
+ /*
|
||||
+ * For some reason, 24 bits wide audio don't play well
|
||||
+ * if the 32 bits mode is not set
|
||||
+ */
|
||||
+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_32BIT);
|
||||
+ break;
|
||||
+ case 16:
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ switch (channels) {
|
||||
+ case 2: /* Nothing to do */
|
||||
+ break;
|
||||
+ case 8:
|
||||
+ /* TODO: Still requires testing ... */
|
||||
+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC,
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_8CH |
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_24BIT |
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_32BIT,
|
||||
+ desc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ unsigned int width = params_width(params);
|
||||
+ unsigned int channels = params_channels(params);
|
||||
+ unsigned int rate = params_rate(params);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __setup_desc(priv, width, channels);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable set to set i2s description\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = __bclks_set_rate(priv, rate, width);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable set to the i2s clock rates\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ u32 val;
|
||||
+
|
||||
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* DAI output mode */
|
||||
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
+ case SND_SOC_DAIFMT_I2S:
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_I2S;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_LEFT_J:
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_LEFT_J;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_RIGHT_J:
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_RIGHT_J;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_ALRCLK_SKEW_MASK,
|
||||
+ val);
|
||||
+
|
||||
+ /* DAI clock polarity */
|
||||
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
+ case SND_SOC_DAIFMT_IB_IF:
|
||||
+ /* Invert both clocks */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_IB_NF:
|
||||
+ /* Invert bit clock */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_NB_IF:
|
||||
+ /* Invert frame clock */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_NB_NF:
|
||||
+ /* Normal clocks */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_ALRCLK_POLARITY_MASK |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_MASK,
|
||||
+ val);
|
||||
+
|
||||
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
|
||||
+ case SND_SOC_DAIFMT_CONT:
|
||||
+ priv->bclks_idle = true;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_GATED:
|
||||
+ priv->bclks_idle = false;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
+ unsigned int freq, int dir)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ if (WARN_ON(clk_id != 0))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (dir == SND_SOC_CLOCK_IN)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = clk_set_rate(priv->mclk, freq);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Power up the i2s fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ goto out_clk_fast;
|
||||
+
|
||||
+ /* Make sure nothing gets out of the DAI yet */
|
||||
+ __hold(priv, true);
|
||||
+
|
||||
+ /* I2S encoder needs the mixer interface gate */
|
||||
+ ret = clk_prepare_enable(priv->iface);
|
||||
+ if (ret)
|
||||
+ goto out_clk_iface;
|
||||
+
|
||||
+ /* Enable the i2s master clock */
|
||||
+ ret = clk_prepare_enable(priv->mclk);
|
||||
+ if (ret)
|
||||
+ goto out_mclk;
|
||||
+
|
||||
+ /* Enable the bit clock gate */
|
||||
+ ret = clk_prepare_enable(priv->bclks);
|
||||
+ if (ret)
|
||||
+ goto out_bclks;
|
||||
+
|
||||
+ /* Make sure the interface expect a memory layout we can work with */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC,
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_bclks:
|
||||
+ clk_disable_unprepare(priv->mclk);
|
||||
+out_mclk:
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+out_clk_iface:
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+out_clk_fast:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void meson_i2s_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->bclks);
|
||||
+ clk_disable_unprepare(priv->mclk);
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops meson_i2s_dai_ops = {
|
||||
+ .startup = meson_i2s_dai_startup,
|
||||
+ .shutdown = meson_i2s_dai_shutdown,
|
||||
+ .trigger = meson_i2s_dai_trigger,
|
||||
+ .hw_params = meson_i2s_dai_hw_params,
|
||||
+ .set_fmt = meson_i2s_dai_set_fmt,
|
||||
+ .set_sysclk = meson_i2s_dai_set_sysclk,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver meson_i2s_dai = {
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 8,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_192000,
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE)
|
||||
+ },
|
||||
+ .ops = &meson_i2s_dai_ops,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver meson_i2s_dai_component = {
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int meson_i2s_dai_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct meson_i2s_dai *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get the i2s fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->iface = devm_clk_get(dev, "iface");
|
||||
+ if (IS_ERR(priv->iface)) {
|
||||
+ if (PTR_ERR(priv->iface) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get i2s dai clock gate\n");
|
||||
+ return PTR_ERR(priv->iface);
|
||||
+ }
|
||||
+
|
||||
+ priv->bclks = devm_clk_get(dev, "bclks");
|
||||
+ if (IS_ERR(priv->bclks)) {
|
||||
+ if (PTR_ERR(priv->bclks) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get bit clocks gate\n");
|
||||
+ return PTR_ERR(priv->bclks);
|
||||
+ }
|
||||
+
|
||||
+ priv->mclk = devm_clk_get(dev, "mclk");
|
||||
+ if (IS_ERR(priv->mclk)) {
|
||||
+ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "failed to get the i2s master clock\n");
|
||||
+ return PTR_ERR(priv->mclk);
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &meson_i2s_dai_component,
|
||||
+ &meson_i2s_dai, 1);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id meson_i2s_dai_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-i2s-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-i2s-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxl-i2s-dai", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, meson_i2s_dai_of_match);
|
||||
+
|
||||
+static struct platform_driver meson_i2s_dai_pdrv = {
|
||||
+ .probe = meson_i2s_dai_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = meson_i2s_dai_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_i2s_dai_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson i2s DAI ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,438 @@
|
||||
From 8dd5edaf984e4c8d6f7ca1e7709b3109cf7dd780 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 13:43:52 +0200
|
||||
Subject: [PATCH] ASoC: meson: add aiu spdif dma support
|
||||
|
||||
Add support for the spdif output dma which is part of the AIU block
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 7 +
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/aiu-spdif-dma.c | 388 ++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 397 insertions(+)
|
||||
create mode 100644 sound/soc/meson/aiu-spdif-dma.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 478f29a..3fb93b9 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -14,3 +14,10 @@ config SND_SOC_MESON_I2S
|
||||
help
|
||||
Say Y or M if you want to add support for i2s driver for Amlogic
|
||||
Meson SoCs.
|
||||
+
|
||||
+config SND_SOC_MESON_SPDIF
|
||||
+ tristate "Meson spdif interface"
|
||||
+ depends on SND_SOC_MESON
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for spdif dma driver for Amlogic
|
||||
+ Meson SoCs.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index ea06dde..cef9a9d 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -1,7 +1,9 @@
|
||||
snd-soc-meson-audio-core-objs := audio-core.o
|
||||
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
|
||||
+snd-soc-meson-aiu-spdif-dma-objs := aiu-spdif-dma.o
|
||||
snd-soc-meson-i2s-dai-objs := i2s-dai.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
|
||||
+obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
|
||||
diff --git a/sound/soc/meson/aiu-spdif-dma.c b/sound/soc/meson/aiu-spdif-dma.c
|
||||
new file mode 100644
|
||||
index 0000000..81c3b85
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-spdif-dma.c
|
||||
@@ -0,0 +1,388 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-aiu-spdif-dma"
|
||||
+
|
||||
+struct aiu_spdif_dma {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *fast;
|
||||
+ int irq;
|
||||
+};
|
||||
+
|
||||
+#define AIU_958_DCU_FF_CTRL_EN BIT(0)
|
||||
+#define AIU_958_DCU_FF_CTRL_AUTO_DISABLE BIT(1)
|
||||
+#define AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK GENMASK(3, 2)
|
||||
+#define AIU_958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2)
|
||||
+#define AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3)
|
||||
+#define AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4)
|
||||
+#define AIU_958_DCU_FF_CTRL_BYTE_SEEK BIT(5)
|
||||
+#define AIU_958_DCU_FF_CTRL_CONTINUE BIT(6)
|
||||
+#define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0)
|
||||
+#define AIU_MEM_IEC958_CONTROL_INIT BIT(0)
|
||||
+#define AIU_MEM_IEC958_CONTROL_FILL_EN BIT(1)
|
||||
+#define AIU_MEM_IEC958_CONTROL_EMPTY_EN BIT(2)
|
||||
+#define AIU_MEM_IEC958_CONTROL_ENDIAN_MASK GENMASK(5, 3)
|
||||
+#define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6)
|
||||
+#define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_MEM_MASK GENMASK(15, 8)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_MEM(ch) ((ch) << 8)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_RD_MASK GENMASK(7, 0)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_RD(ch) ((ch) << 0)
|
||||
+
|
||||
+#define AIU_SPDIF_DMA_BURST 8
|
||||
+#define AIU_SPDIF_BPF_MAX USHRT_MAX
|
||||
+
|
||||
+static struct snd_pcm_hardware aiu_spdif_dma_hw = {
|
||||
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID |
|
||||
+ SNDRV_PCM_INFO_PAUSE),
|
||||
+
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE),
|
||||
+
|
||||
+ .rates = (SNDRV_PCM_RATE_32000 |
|
||||
+ SNDRV_PCM_RATE_44100 |
|
||||
+ SNDRV_PCM_RATE_48000 |
|
||||
+ SNDRV_PCM_RATE_96000 |
|
||||
+ SNDRV_PCM_RATE_192000),
|
||||
+ /*
|
||||
+ * TODO: The DMA can change the endianness, the msb position
|
||||
+ * and deal with unsigned - support this later on
|
||||
+ */
|
||||
+
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .period_bytes_min = AIU_SPDIF_DMA_BURST,
|
||||
+ .period_bytes_max = AIU_SPDIF_BPF_MAX,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = UINT_MAX,
|
||||
+ .buffer_bytes_max = 1 * 1024 * 1024,
|
||||
+ .fifo_size = 0,
|
||||
+};
|
||||
+
|
||||
+static struct aiu_spdif_dma *aiu_spdif_dma_priv(struct snd_pcm_substream *s)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = s->private_data;
|
||||
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
+
|
||||
+ return snd_soc_component_get_drvdata(component);
|
||||
+}
|
||||
+
|
||||
+static snd_pcm_uframes_t
|
||||
+aiu_spdif_dma_pointer(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+ unsigned int addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_read(priv->core->aiu, AIU_MEM_IEC958_RD_PTR,
|
||||
+ &addr);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
|
||||
+}
|
||||
+
|
||||
+static void __dma_enable(struct aiu_spdif_dma *priv, bool enable)
|
||||
+{
|
||||
+ unsigned int en_mask = (AIU_MEM_IEC958_CONTROL_FILL_EN |
|
||||
+ AIU_MEM_IEC958_CONTROL_EMPTY_EN);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, en_mask,
|
||||
+ enable ? en_mask : 0);
|
||||
+}
|
||||
+
|
||||
+static void __dcu_fifo_enable(struct aiu_spdif_dma *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL,
|
||||
+ AIU_958_DCU_FF_CTRL_EN,
|
||||
+ enable ? AIU_958_DCU_FF_CTRL_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __dcu_fifo_enable(priv, true);
|
||||
+ __dma_enable(priv, true);
|
||||
+ break;
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ __dma_enable(priv, false);
|
||||
+ __dcu_fifo_enable(priv, false);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __dma_init_mem(struct aiu_spdif_dma *priv)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_INIT,
|
||||
+ AIU_MEM_IEC958_CONTROL_INIT);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL,
|
||||
+ AIU_MEM_IEC958_BUF_CNTL_INIT,
|
||||
+ AIU_MEM_IEC958_BUF_CNTL_INIT);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_INIT,
|
||||
+ 0);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL,
|
||||
+ AIU_MEM_IEC958_BUF_CNTL_INIT,
|
||||
+ 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+
|
||||
+ __dma_init_mem(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __setup_memory_layout(struct aiu_spdif_dma *priv,
|
||||
+ unsigned int width)
|
||||
+{
|
||||
+ u32 mem_ctl = AIU_MEM_IEC958_CONTROL_RD_DDR;
|
||||
+
|
||||
+ if (width == 16)
|
||||
+ mem_ctl |= AIU_MEM_IEC958_CONTROL_MODE_16BIT;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_ENDIAN_MASK |
|
||||
+ AIU_MEM_IEC958_CONTROL_MODE_16BIT |
|
||||
+ AIU_MEM_IEC958_CONTROL_RD_DDR,
|
||||
+ mem_ctl);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+ int ret;
|
||||
+ dma_addr_t end_ptr;
|
||||
+
|
||||
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = __setup_memory_layout(priv, params_physical_width(params));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Initialize memory pointers */
|
||||
+ regmap_write(priv->core->aiu,
|
||||
+ AIU_MEM_IEC958_START_PTR, runtime->dma_addr);
|
||||
+ regmap_write(priv->core->aiu,
|
||||
+ AIU_MEM_IEC958_RD_PTR, runtime->dma_addr);
|
||||
+
|
||||
+ /* The end pointer is the address of the last valid block */
|
||||
+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_SPDIF_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_IEC958_END_PTR, end_ptr);
|
||||
+
|
||||
+ /* Memory masks */
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_IEC958_MASKS,
|
||||
+ AIU_MEM_IEC958_MASKS_CH_RD(0xff) |
|
||||
+ AIU_MEM_IEC958_MASKS_CH_MEM(0xff));
|
||||
+
|
||||
+ /* Setup the number bytes read by the FIFO between each IRQ */
|
||||
+ regmap_write(priv->core->aiu, AIU_958_BPF, params_period_bytes(params));
|
||||
+
|
||||
+ /*
|
||||
+ * AUTO_DISABLE and SYNC_HEAD are enabled by default but
|
||||
+ * this should be disabled in PCM (uncompressed) mode
|
||||
+ */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL,
|
||||
+ AIU_958_DCU_FF_CTRL_AUTO_DISABLE |
|
||||
+ AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK |
|
||||
+ AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN,
|
||||
+ AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ return snd_pcm_lib_free_pages(substream);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t aiu_spdif_dma_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct snd_pcm_substream *playback = dev_id;
|
||||
+
|
||||
+ snd_pcm_period_elapsed(playback);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+ int ret;
|
||||
+
|
||||
+ snd_soc_set_runtime_hwparams(substream, &aiu_spdif_dma_hw);
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the buffer and period size are multiple of the DMA burst
|
||||
+ * size
|
||||
+ */
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
+ AIU_SPDIF_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
||||
+ AIU_SPDIF_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Request the SPDIF DDR irq */
|
||||
+ ret = request_irq(priv->irq, aiu_spdif_dma_irq, 0,
|
||||
+ DRV_NAME, substream);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Power up the spdif fast domain - can't write the register w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Make sure the dma is initially halted */
|
||||
+ __dma_enable(priv, false);
|
||||
+ __dcu_fifo_enable(priv, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+ free_irq(priv->irq, substream);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_pcm_ops aiu_spdif_dma_ops = {
|
||||
+ .open = aiu_spdif_dma_open,
|
||||
+ .close = aiu_spdif_dma_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = aiu_spdif_dma_hw_params,
|
||||
+ .hw_free = aiu_spdif_dma_hw_free,
|
||||
+ .prepare = aiu_spdif_dma_prepare,
|
||||
+ .pointer = aiu_spdif_dma_pointer,
|
||||
+ .trigger = aiu_spdif_dma_trigger,
|
||||
+};
|
||||
+
|
||||
+static int aiu_spdif_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_card *card = rtd->card->snd_card;
|
||||
+ size_t size = aiu_spdif_dma_hw.buffer_bytes_max;
|
||||
+
|
||||
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
+ SNDRV_DMA_TYPE_DEV,
|
||||
+ card->dev, size, size);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver aiu_spdif_platform = {
|
||||
+ .ops = &aiu_spdif_dma_ops,
|
||||
+ .pcm_new = aiu_spdif_dma_new,
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int aiu_spdif_dma_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct aiu_spdif_dma *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get spdif fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->irq = platform_get_irq(pdev, 0);
|
||||
+ if (priv->irq <= 0) {
|
||||
+ dev_err(dev, "Can't get spdif ddr irq\n");
|
||||
+ return priv->irq;
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &aiu_spdif_platform,
|
||||
+ NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id aiu_spdif_dma_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-aiu-spdif-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-aiu-spdif-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxl-aiu-spdif-dma", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, aiu_spdif_dma_of_match);
|
||||
+
|
||||
+static struct platform_driver aiu_spdif_dma_pdrv = {
|
||||
+ .probe = aiu_spdif_dma_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = aiu_spdif_dma_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(aiu_spdif_dma_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson AIU spdif DMA ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,426 @@
|
||||
From e635299f76dc27b97a768f2a044d04c1917b9ad1 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 13:46:03 +0200
|
||||
Subject: [PATCH] ASoC: meson: add initial spdif dai support
|
||||
|
||||
Add support for the spdif dai found on Amlogic Meson SoC family.
|
||||
With this initial implementation, only uncompressed pcm playback
|
||||
from the spdif dma is supported. Future work will add compressed
|
||||
support, pcm playback from i2s dma and capture.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 3 +-
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/spdif-dai.c | 374 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 378 insertions(+), 1 deletion(-)
|
||||
create mode 100644 sound/soc/meson/spdif-dai.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 3fb93b9..301d3a3 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -18,6 +18,7 @@ config SND_SOC_MESON_I2S
|
||||
config SND_SOC_MESON_SPDIF
|
||||
tristate "Meson spdif interface"
|
||||
depends on SND_SOC_MESON
|
||||
+ select SND_PCM_IEC958
|
||||
help
|
||||
- Say Y or M if you want to add support for spdif dma driver for Amlogic
|
||||
+ Say Y or M if you want to add support for spdif driver for Amlogic
|
||||
Meson SoCs.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index cef9a9d..bc4391c 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -2,8 +2,10 @@ snd-soc-meson-audio-core-objs := audio-core.o
|
||||
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
|
||||
snd-soc-meson-aiu-spdif-dma-objs := aiu-spdif-dma.o
|
||||
snd-soc-meson-i2s-dai-objs := i2s-dai.o
|
||||
+snd-soc-meson-spdif-dai-objs := spdif-dai.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
|
||||
obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
|
||||
+obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-spdif-dai.o
|
||||
diff --git a/sound/soc/meson/spdif-dai.c b/sound/soc/meson/spdif-dai.c
|
||||
new file mode 100644
|
||||
index 0000000..e763000
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/spdif-dai.c
|
||||
@@ -0,0 +1,374 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+#include <sound/pcm_iec958.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-spdif-dai"
|
||||
+
|
||||
+struct meson_spdif_dai {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *iface;
|
||||
+ struct clk *fast;
|
||||
+ struct clk *mclk_i958;
|
||||
+ struct clk *mclk;
|
||||
+};
|
||||
+
|
||||
+#define AIU_CLK_CTRL_958_DIV_EN BIT(1)
|
||||
+#define AIU_CLK_CTRL_958_DIV_MASK GENMASK(5, 4)
|
||||
+#define AIU_CLK_CTRL_958_DIV_MORE BIT(12)
|
||||
+#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8)
|
||||
+#define AIU_958_CTRL_HOLD_EN BIT(0)
|
||||
+#define AIU_958_MISC_NON_PCM BIT(0)
|
||||
+#define AIU_958_MISC_MODE_16BITS BIT(1)
|
||||
+#define AIU_958_MISC_16BITS_ALIGN_MASK GENMASK(6, 5)
|
||||
+#define AIU_958_MISC_16BITS_ALIGN(val) ((val) << 5)
|
||||
+#define AIU_958_MISC_MODE_32BITS BIT(7)
|
||||
+#define AIU_958_MISC_32BITS_SHIFT_MASK GENMASK(10, 8)
|
||||
+#define AIU_958_MISC_32BITS_SHIFT(val) ((val) << 8)
|
||||
+#define AIU_958_MISC_U_FROM_STREAM BIT(12)
|
||||
+#define AIU_958_MISC_FORCE_LR BIT(13)
|
||||
+
|
||||
+#define AIU_CS_WORD_LEN 4
|
||||
+
|
||||
+static void __hold(struct meson_spdif_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_CTRL,
|
||||
+ AIU_958_CTRL_HOLD_EN,
|
||||
+ enable ? AIU_958_CTRL_HOLD_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __divider_enable(struct meson_spdif_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_958_DIV_EN,
|
||||
+ enable ? AIU_CLK_CTRL_958_DIV_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __playback_start(struct meson_spdif_dai *priv)
|
||||
+{
|
||||
+ __divider_enable(priv, true);
|
||||
+ __hold(priv, false);
|
||||
+}
|
||||
+
|
||||
+static void __playback_stop(struct meson_spdif_dai *priv)
|
||||
+{
|
||||
+ __hold(priv, true);
|
||||
+ __divider_enable(priv, false);
|
||||
+}
|
||||
+
|
||||
+static int meson_spdif_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __playback_start(priv);
|
||||
+ return 0;
|
||||
+
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ __playback_stop(priv);
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int __setup_spdif_clk(struct meson_spdif_dai *priv, unsigned int rate)
|
||||
+{
|
||||
+ unsigned int mrate;
|
||||
+
|
||||
+ /* Leave the internal divisor alone */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_958_DIV_MASK |
|
||||
+ AIU_CLK_CTRL_958_DIV_MORE,
|
||||
+ 0);
|
||||
+
|
||||
+ /* 2 * 32bits per subframe * 2 channels = 128 */
|
||||
+ mrate = rate * 128;
|
||||
+ return clk_set_rate(priv->mclk, mrate);
|
||||
+}
|
||||
+
|
||||
+static int __setup_cs_word(struct meson_spdif_dai *priv,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ u8 cs[AIU_CS_WORD_LEN];
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = snd_pcm_create_iec958_consumer_hw_params(params, cs,
|
||||
+ AIU_CS_WORD_LEN);
|
||||
+ if (ret < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* Write the 1st half word */
|
||||
+ val = cs[1] | cs[0] << 8;
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L0, val);
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R0, val);
|
||||
+
|
||||
+ /* Write the 2nd half word */
|
||||
+ val = cs[3] | cs[2] << 8;
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L1, val);
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R1, val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __setup_pcm_fmt(struct meson_spdif_dai *priv,
|
||||
+ unsigned int width)
|
||||
+{
|
||||
+ u32 val = 0;
|
||||
+
|
||||
+ switch (width) {
|
||||
+ case 16:
|
||||
+ val |= AIU_958_MISC_MODE_16BITS;
|
||||
+ val |= AIU_958_MISC_16BITS_ALIGN(2);
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ case 24:
|
||||
+ /*
|
||||
+ * Looks like this should only be set for 32bits mode, but the
|
||||
+ * vendor kernel sets it like this for 24bits as well, let's
|
||||
+ * try and see
|
||||
+ */
|
||||
+ val |= AIU_958_MISC_MODE_32BITS;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* No idea what this actually does, copying the vendor kernel for now */
|
||||
+ val |= AIU_958_MISC_FORCE_LR;
|
||||
+ val |= AIU_958_MISC_U_FROM_STREAM;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_MISC,
|
||||
+ AIU_958_MISC_NON_PCM |
|
||||
+ AIU_958_MISC_MODE_16BITS |
|
||||
+ AIU_958_MISC_16BITS_ALIGN_MASK |
|
||||
+ AIU_958_MISC_MODE_32BITS |
|
||||
+ AIU_958_MISC_FORCE_LR,
|
||||
+ val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_spdif_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __setup_spdif_clk(priv, params_rate(params));
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable to set the spdif clock\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = __setup_cs_word(priv, params);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable to set the channel status word\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = __setup_pcm_fmt(priv, params_width(params));
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable to set the pcm format\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_spdif_dai_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Power up the spdif fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ goto out_clk_fast;
|
||||
+
|
||||
+ /* Make sure nothing gets out of the DAI yet*/
|
||||
+ __hold(priv, true);
|
||||
+
|
||||
+ ret = clk_set_parent(priv->mclk, priv->mclk_i958);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Enable the clock gate */
|
||||
+ ret = clk_prepare_enable(priv->iface);
|
||||
+ if (ret)
|
||||
+ goto out_clk_iface;
|
||||
+
|
||||
+ /* Enable the spdif clock */
|
||||
+ ret = clk_prepare_enable(priv->mclk);
|
||||
+ if (ret)
|
||||
+ goto out_mclk;
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the interface expect a memory layout we can work with
|
||||
+ * MEM prefixed register usually belong to the DMA, but when the spdif
|
||||
+ * DAI takes data from the i2s buffer, we need to make sure it works in
|
||||
+ * split mode and not the "normal mode" (channel samples packed in
|
||||
+ * 32 bytes groups)
|
||||
+ */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_MODE_LINEAR,
|
||||
+ AIU_MEM_IEC958_CONTROL_MODE_LINEAR);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_mclk:
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+out_clk_iface:
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+out_clk_fast:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void meson_spdif_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+ clk_disable_unprepare(priv->mclk);
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops meson_spdif_dai_ops = {
|
||||
+ .startup = meson_spdif_dai_startup,
|
||||
+ .shutdown = meson_spdif_dai_shutdown,
|
||||
+ .trigger = meson_spdif_dai_trigger,
|
||||
+ .hw_params = meson_spdif_dai_hw_params,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver meson_spdif_dai = {
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = (SNDRV_PCM_RATE_32000 |
|
||||
+ SNDRV_PCM_RATE_44100 |
|
||||
+ SNDRV_PCM_RATE_48000 |
|
||||
+ SNDRV_PCM_RATE_96000 |
|
||||
+ SNDRV_PCM_RATE_192000),
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE)
|
||||
+ },
|
||||
+ .ops = &meson_spdif_dai_ops,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver meson_spdif_dai_component = {
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int meson_spdif_dai_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct meson_spdif_dai *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get spdif fast domain clockt\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->iface = devm_clk_get(dev, "iface");
|
||||
+ if (IS_ERR(priv->iface)) {
|
||||
+ if (PTR_ERR(priv->iface) != -EPROBE_DEFER)
|
||||
+ dev_err(dev,
|
||||
+ "Can't get the dai clock gate\n");
|
||||
+ return PTR_ERR(priv->iface);
|
||||
+ }
|
||||
+
|
||||
+ priv->mclk_i958 = devm_clk_get(dev, "mclk_i958");
|
||||
+ if (IS_ERR(priv->mclk_i958)) {
|
||||
+ if (PTR_ERR(priv->mclk_i958) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get the spdif master clock\n");
|
||||
+ return PTR_ERR(priv->mclk_i958);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * TODO: the spdif dai can also get its data from the i2s fifo.
|
||||
+ * For this use-case, the DAI driver will need to get the i2s master
|
||||
+ * clock in order to reparent the spdif clock from cts_mclk_i958 to
|
||||
+ * cts_amclk
|
||||
+ */
|
||||
+
|
||||
+ priv->mclk = devm_clk_get(dev, "mclk");
|
||||
+ if (IS_ERR(priv->mclk)) {
|
||||
+ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get the spdif input mux clock\n");
|
||||
+ return PTR_ERR(priv->mclk);
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &meson_spdif_dai_component,
|
||||
+ &meson_spdif_dai, 1);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id meson_spdif_dai_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-spdif-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-spdif-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxl-spdif-dai", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, meson_spdif_dai_of_match);
|
||||
+
|
||||
+static struct platform_driver meson_spdif_dai_pdrv = {
|
||||
+ .probe = meson_spdif_dai_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = meson_spdif_dai_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_spdif_dai_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson spdif DAI ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,29 @@
|
||||
From 5ddca63ac5c5d81c6d6a6745670a3f136970eaef Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 31 Mar 2017 15:55:03 +0200
|
||||
Subject: [PATCH] ARM64: defconfig: enable audio support for meson SoCs as
|
||||
module
|
||||
|
||||
Add audio support for meson SoCs. This includes the audio core
|
||||
driver and the i2s and spdif output interfaces
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/configs/defconfig | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
|
||||
index 2584605..ae1f774 100644
|
||||
--- a/arch/arm64/configs/defconfig
|
||||
+++ b/arch/arm64/configs/defconfig
|
||||
@@ -451,6 +451,10 @@ CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_SND_SOC=y
|
||||
CONFIG_SND_BCM2835_SOC_I2S=m
|
||||
+CONFIG_SND_SOC_MESON=m
|
||||
+CONFIG_SND_SOC_MESON_I2S=m
|
||||
+CONFIG_SND_SOC_MESON_SPDIF=m
|
||||
+CONFIG_SND_SOC_RCAR=y
|
||||
CONFIG_SND_SOC_SAMSUNG=y
|
||||
CONFIG_SND_SOC_RCAR=m
|
||||
CONFIG_SND_SOC_AK4613=m
|
@ -0,0 +1,186 @@
|
||||
From f4d7ad156ad2253d5ec3e79ea36309e27b8fabc7 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 15:19:04 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson-gx: add audio controller nodes
|
||||
|
||||
Add audio controller nodes for Amlogic meson gxbb and gxl.
|
||||
This includes the audio-core node, the i2s and spdif DAIs, i2s and spdif
|
||||
aiu DMAs.
|
||||
|
||||
Audio on this SoC family is still a work in progress. More nodes are likely
|
||||
to be added later on (pcm DAIs, input DMAs, etc ...)
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 35 ++++++++++++++++++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 39 +++++++++++++++++++++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 38 ++++++++++++++++++++++++++++
|
||||
3 files changed, 112 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
index b8dc4db..6b64b63 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -203,6 +203,41 @@
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
+ audio: audio@5400 {
|
||||
+ compatible = "amlogic,meson-audio-core";
|
||||
+ reg = <0x0 0x5400 0x0 0x2ac>,
|
||||
+ <0x0 0xa000 0x0 0x304>;
|
||||
+ reg-names = "aiu", "audin";
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ aiu_i2s_dma: aiu_i2s_dma {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-aiu-i2s-dma";
|
||||
+ interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ aiu_spdif_dma: aiu_spdif_dma {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-aiu-spdif-dma";
|
||||
+ interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ i2s_dai: i2s_dai {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-i2s-dai";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ spdif_dai: spdif_dai {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-spdif-dai";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ };
|
||||
+
|
||||
uart_A: serial@84c0 {
|
||||
compatible = "amlogic,meson-gx-uart";
|
||||
reg = <0x0 0x84c0 0x0 0x18>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 98cbba6..7913249 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -659,6 +659,35 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ clocks = <&clkc CLKID_AIU>,
|
||||
+ <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_SPDIF>;
|
||||
+ clock-names = "aiu_top", "aiu_glue", "audin";
|
||||
+ resets = <&reset RESET_AIU>,
|
||||
+ <&reset RESET_AUDIN>;
|
||||
+ reset-names = "aiu", "audin";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>;
|
||||
+ clock-names = "fast";
|
||||
+};
|
||||
+
|
||||
+&aiu_spdif_dma {
|
||||
+ clocks = <&clkc CLKID_IEC958>;
|
||||
+ clock-names = "fast";
|
||||
+
|
||||
+};
|
||||
+
|
||||
+&i2s_dai {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>;
|
||||
+ clock-names = "fast", "iface", "bclks", "mclk";
|
||||
+};
|
||||
+
|
||||
&pwrc_vpu {
|
||||
resets = <&reset RESET_VIU>,
|
||||
<&reset RESET_VENC>,
|
||||
@@ -741,6 +770,15 @@
|
||||
num-cs = <1>;
|
||||
};
|
||||
|
||||
+&spdif_dai {
|
||||
+ clocks = <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk";
|
||||
+};
|
||||
+
|
||||
&spifc {
|
||||
clocks = <&clkc CLKID_SPI>;
|
||||
};
|
||||
@@ -774,3 +812,4 @@
|
||||
compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
+
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index c87a80e..20922cd 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -660,6 +660,34 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ clocks = <&clkc CLKID_AIU>,
|
||||
+ <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_SPDIF>;
|
||||
+ clock-names = "aiu_top", "aiu_glue", "audin";
|
||||
+ resets = <&reset RESET_AIU>,
|
||||
+ <&reset RESET_AUDIN>;
|
||||
+ reset-names = "aiu", "audin";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>;
|
||||
+ clock-names = "fast";
|
||||
+};
|
||||
+
|
||||
+&aiu_spdif_dma {
|
||||
+ clocks = <&clkc CLKID_IEC958>;
|
||||
+ clock-names = "fast";
|
||||
+};
|
||||
+
|
||||
+&i2s_dai {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>;
|
||||
+ clock-names = "fast", "iface", "bclks", "mclk";
|
||||
+};
|
||||
+
|
||||
&pwrc_vpu {
|
||||
resets = <&reset RESET_VIU>,
|
||||
<&reset RESET_VENC>,
|
||||
@@ -742,6 +770,15 @@
|
||||
num-cs = <1>;
|
||||
};
|
||||
|
||||
+&spdif_dai {
|
||||
+ clocks = <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk";
|
||||
+};
|
||||
+
|
||||
&spifc {
|
||||
clocks = <&clkc CLKID_SPI>;
|
||||
};
|
||||
@@ -775,3 +812,4 @@
|
||||
compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
+
|
@ -0,0 +1,52 @@
|
||||
From 69d2f200d91fbd48e2388a8c5346f10d889a2928 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:39:21 +0200
|
||||
Subject: [PATCH] snd: meson: activate HDMI audio path
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/i2s-dai.c | 22 ++++++++++++++++++++++
|
||||
1 file changed, 22 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
|
||||
index 1008af8..63fe098 100644
|
||||
--- a/sound/soc/meson/i2s-dai.c
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -56,8 +56,19 @@ struct meson_i2s_dai {
|
||||
#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8)
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0)
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK BIT(6)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_I958_CLK (0 << 6)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK (1 << 6)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK GENMASK(1, 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_DISABLE (0 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_PCM (1 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_I2S (2 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK GENMASK(5, 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_MUTE (0 << 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_PCM (1 << 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_I2S (2 << 4)
|
||||
#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0)
|
||||
#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0)
|
||||
#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0)
|
||||
@@ -221,6 +232,17 @@ static int meson_i2s_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /* Quick and dirty hack for HDMI */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_HDMI_CLK_DATA_CTRL,
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK |
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK,
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_CLK_I2S |
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_DATA_I2S);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE,
|
||||
+ AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK,
|
||||
+ AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
From 223d7ef1a49981c597094e8519e150108cba9ef9 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 14 Feb 2017 19:18:04 +0100
|
||||
Subject: [PATCH] drm/meson: select dw-hdmi i2s audio for meson hdmi
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/Kconfig | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
|
||||
index 3ce51d8..02d400b 100644
|
||||
--- a/drivers/gpu/drm/meson/Kconfig
|
||||
+++ b/drivers/gpu/drm/meson/Kconfig
|
||||
@@ -13,3 +13,4 @@ config DRM_MESON_DW_HDMI
|
||||
depends on DRM_MESON
|
||||
default y if DRM_MESON
|
||||
select DRM_DW_HDMI
|
||||
+ select DRM_DW_HDMI_I2S_AUDIO
|
@ -0,0 +1,35 @@
|
||||
From 00ce6fbb804c6aaecd3bde8f2978d091fbc0546c Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 20 Sep 2017 18:01:26 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson-gx: add sound-dai-cells to HDMI node
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 +
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 7913249..2a4d506 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -305,6 +305,7 @@
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
+ #sound-dai-cells = <0>;
|
||||
};
|
||||
|
||||
&sysctrl {
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index 20922cd..9f4b618 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -257,6 +257,7 @@
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
+ #sound-dai-cells = <0>;
|
||||
};
|
||||
|
||||
&sysctrl {
|
@ -0,0 +1,860 @@
|
||||
From 2df1a3a93bc1ce2d04fa0f0743c9c30195c7057a Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 20 Sep 2017 18:10:08 +0200
|
||||
Subject: [PATCH] ARM64: dts: meson: activate hdmi audio HDMI enabled boards
|
||||
|
||||
This patch activate audio over HDMI on selected boards
|
||||
|
||||
Please note that this audio support is based on WIP changes
|
||||
This should be considered as preview and it does not reflect
|
||||
the audio I expect to see merged
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 45 ++++++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 45 ++++++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts | 45 ++++++++++++++++++++++
|
||||
.../arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 45 ++++++++++++++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 45 ++++++++++++++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi | 45 ++++++++++++++++++++++
|
||||
.../dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 45 ++++++++++++++++++++++
|
||||
.../dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 45 ++++++++++++++++++++++
|
||||
.../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts | 45 ++++++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 45 ++++++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 45 ++++++++++++++++++++++
|
||||
.../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 45 ++++++++++++++++++++++
|
||||
12 files changed, 540 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
index 88e712e..319512e 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
@@ -95,6 +95,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -104,6 +137,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -126,6 +167,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
index cbe99bd..5b10de9 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
@@ -88,6 +88,39 @@
|
||||
clock-names = "ext_clock";
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
vcc1v8: regulator-vcc1v8 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VCC1.8V";
|
||||
@@ -131,6 +164,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cec_AO {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&ao_cec_pins>;
|
||||
@@ -185,6 +226,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
|
||||
index 4cf7f6e..ff87bdc 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
|
||||
@@ -119,6 +119,39 @@
|
||||
clock-names = "ext_clock";
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
cvbs-connector {
|
||||
compatible = "composite-video-connector";
|
||||
|
||||
@@ -154,6 +187,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-0 = <ð_rmii_pins>;
|
||||
@@ -190,6 +231,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 54954b3..3da3309 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -110,6 +110,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -119,6 +152,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-0 = <ð_rgmii_pins>;
|
||||
@@ -181,6 +222,10 @@
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
index ce86226..84eb93b 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
@@ -113,6 +113,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -122,6 +155,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -140,6 +181,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
index 70325b2..7d1f172 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
@@ -105,6 +105,47 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -159,6 +200,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
index d32cf38..f053595 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
@@ -65,6 +65,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -74,6 +107,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
@@ -86,6 +127,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&i2c_A {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c_a_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
index f63bceb..f56969e 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
@@ -84,6 +84,39 @@
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
vcc_3v3: regulator-vcc_3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VCC_3V3";
|
||||
@@ -130,6 +163,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -151,6 +192,10 @@
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
|
||||
index 6739697..e3e777f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
|
||||
@@ -102,6 +102,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -111,6 +144,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -135,6 +176,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
index 5896e8a..f8c66a7 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
@@ -32,6 +32,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -41,12 +74,24 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
index 0868da4..ea71261 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
|
||||
@@ -85,6 +85,39 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
|
||||
@@ -205,6 +238,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cpu0 {
|
||||
#cooling-cells = <2>;
|
||||
};
|
||||
@@ -255,6 +296,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&i2c_A {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c_a_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
index f7a1cff..b9c5e64 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
@@ -75,6 +75,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -84,6 +117,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -129,6 +170,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
@ -0,0 +1,75 @@
|
||||
From e282ad866be628951a95d297207c9a5580f4101d Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 2 Jul 2018 12:21:55 +0200
|
||||
Subject: [PATCH] drm: bridge: dw-hdmi: Use AUTO CTS setup mode when non-AHB
|
||||
audio
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 ++++++++++++++++++++-----------
|
||||
1 file changed, 26 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index 3c136f2b..a68ffbb 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -430,8 +430,12 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
|
||||
/* nshift factor = 0 */
|
||||
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
|
||||
|
||||
- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
+ /* Use Auto CTS mode with CTS is unknown */
|
||||
+ if (cts)
|
||||
+ hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
+ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
+ else
|
||||
+ hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3);
|
||||
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
|
||||
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
|
||||
|
||||
@@ -501,24 +505,31 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
|
||||
{
|
||||
unsigned long ftdms = pixel_clk;
|
||||
unsigned int n, cts;
|
||||
+ u8 config3;
|
||||
u64 tmp;
|
||||
|
||||
n = hdmi_compute_n(sample_rate, pixel_clk);
|
||||
|
||||
- /*
|
||||
- * Compute the CTS value from the N value. Note that CTS and N
|
||||
- * can be up to 20 bits in total, so we need 64-bit math. Also
|
||||
- * note that our TDMS clock is not fully accurate; it is accurate
|
||||
- * to kHz. This can introduce an unnecessary remainder in the
|
||||
- * calculation below, so we don't try to warn about that.
|
||||
- */
|
||||
- tmp = (u64)ftdms * n;
|
||||
- do_div(tmp, 128 * sample_rate);
|
||||
- cts = tmp;
|
||||
+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
|
||||
|
||||
- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
|
||||
- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000,
|
||||
- n, cts);
|
||||
+ if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
|
||||
+ /*
|
||||
+ * Compute the CTS value from the N value. Note that CTS and N
|
||||
+ * can be up to 20 bits in total, so we need 64-bit math. Also
|
||||
+ * note that our TDMS clock is not fully accurate; it is
|
||||
+ * accurate to kHz. This can introduce an unnecessary remainder
|
||||
+ * in the calculation below, so we don't try to warn about that.
|
||||
+ */
|
||||
+ tmp = (u64)ftdms * n;
|
||||
+ do_div(tmp, 128 * sample_rate);
|
||||
+ cts = tmp;
|
||||
+
|
||||
+ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
|
||||
+ __func__, sample_rate,
|
||||
+ ftdms / 1000000, (ftdms / 1000) % 1000,
|
||||
+ n, cts);
|
||||
+ } else
|
||||
+ cts = 0;
|
||||
|
||||
spin_lock_irq(&hdmi->audio_lock);
|
||||
hdmi->audio_n = n;
|
@ -0,0 +1,36 @@
|
||||
From 4a3a6d04d4996ff0a0acc8405fdd0b0347a62138 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 28 Feb 2018 16:07:18 +0100
|
||||
Subject: [PATCH] drm/meson: Call drm_crtc_vblank_on / drm_crtc_vblank_off
|
||||
|
||||
Make sure that the CRTC code will call the enable/disable_vblank hooks.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_crtc.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
index 0552020..4dd0df0 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
@@ -102,6 +102,8 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
priv->io_base + _REG(VPP_MISC));
|
||||
|
||||
priv->viu.osd1_enabled = true;
|
||||
+
|
||||
+ drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
@@ -110,6 +112,10 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
|
||||
struct meson_drm *priv = meson_crtc->priv;
|
||||
|
||||
+ DRM_DEBUG_DRIVER("\n");
|
||||
+
|
||||
+ drm_crtc_vblank_off(crtc);
|
||||
+
|
||||
priv->viu.osd1_enabled = false;
|
||||
priv->viu.osd1_commit = false;
|
||||
|
@ -0,0 +1,32 @@
|
||||
From 830bb1ab9ee8999566a4d98086590ac824cdeb4e Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 10 Jul 2018 15:00:45 +0200
|
||||
Subject: [PATCH] media: platform: meson-ao-cec: make busy TX warning silent
|
||||
|
||||
Switch to dev_dbg for the busy TX message to avoid having a flood of:
|
||||
[ 228.064570] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
|
||||
[ 230.368489] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
|
||||
[ 234.208655] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
|
||||
[ 236.512558] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
|
||||
|
||||
This message is only a debug hint and not an error.
|
||||
|
||||
Fixes: 7ec2c0f72cb1 ("media: platform: Add Amlogic Meson AO CEC Controller driver")
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/media/platform/meson/ao-cec.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c
|
||||
index 8040a62..cd4be38 100644
|
||||
--- a/drivers/media/platform/meson/ao-cec.c
|
||||
+++ b/drivers/media/platform/meson/ao-cec.c
|
||||
@@ -524,7 +524,7 @@ static int meson_ao_cec_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
return ret;
|
||||
|
||||
if (reg == TX_BUSY) {
|
||||
- dev_err(&ao_cec->pdev->dev, "%s: busy TX: aborting\n",
|
||||
+ dev_dbg(&ao_cec->pdev->dev, "%s: busy TX: aborting\n",
|
||||
__func__);
|
||||
meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT, &ret);
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
From baa0a8ee8b8a0a14ddab6b14c37846dfed261007 Mon Sep 17 00:00:00 2001
|
||||
From: Koen Kooi <koen@dominion.thruhere.net>
|
||||
Date: Fri, 11 May 2018 13:51:20 +0200
|
||||
Subject: [PATCH] libretech-cc: disable CVBS connector
|
||||
|
||||
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
index f56969e..ac3a150 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
@@ -24,7 +24,8 @@
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
|
||||
- cvbs-connector {
|
||||
+ cvbs_connector: cvbs-connector {
|
||||
+ status = "disabled";
|
||||
compatible = "composite-video-connector";
|
||||
|
||||
port {
|
@ -0,0 +1,161 @@
|
||||
From e18fe49cfa5a989d0e8aca1b95a989f71c1916e7 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 19 Jun 2018 11:03:03 +0200
|
||||
Subject: [PATCH] clk: qcom: drop CLK_SET_RATE_GATE from sdc clocks
|
||||
|
||||
the mmci driver (drivers/mmc/host/mmci.c) does the following sequence:
|
||||
* clk_prepare_enable()
|
||||
* clk_set_rate()
|
||||
|
||||
on SDCx_clk which is a children of SDCx_src. SDCx_src has
|
||||
CLK_SET_RATE_GATE so this sequence should not be allowed but this was not
|
||||
enforced. IOW, the flag is ignored. Dropping the flag won't change
|
||||
anything to the current behaviour of the platform.
|
||||
|
||||
CLK_SET_RATE_GATE is being fixed and enforced now. If the flag was kept,
|
||||
the mmci driver would receive -EBUSY when calling clk_set_rate()
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/qcom/gcc-ipq806x.c | 3 ---
|
||||
drivers/clk/qcom/gcc-mdm9615.c | 2 --
|
||||
drivers/clk/qcom/gcc-msm8660.c | 5 -----
|
||||
drivers/clk/qcom/gcc-msm8960.c | 5 -----
|
||||
4 files changed, 15 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
|
||||
index 28eb200d0f1ee..5f61225657abb 100644
|
||||
--- a/drivers/clk/qcom/gcc-ipq806x.c
|
||||
+++ b/drivers/clk/qcom/gcc-ipq806x.c
|
||||
@@ -1220,7 +1220,6 @@ static struct clk_rcg sdc1_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1269,7 +1268,6 @@ static struct clk_rcg sdc3_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1353,7 +1351,6 @@ static struct clk_rcg tsif_ref_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c
|
||||
index b99dd406e9071..849046fbed6d4 100644
|
||||
--- a/drivers/clk/qcom/gcc-mdm9615.c
|
||||
+++ b/drivers/clk/qcom/gcc-mdm9615.c
|
||||
@@ -947,7 +947,6 @@ static struct clk_rcg sdc1_src = {
|
||||
.parent_names = gcc_cxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -996,7 +995,6 @@ static struct clk_rcg sdc2_src = {
|
||||
.parent_names = gcc_cxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c
|
||||
index c347a0d44bc8b..7e930e25c79f1 100644
|
||||
--- a/drivers/clk/qcom/gcc-msm8660.c
|
||||
+++ b/drivers/clk/qcom/gcc-msm8660.c
|
||||
@@ -1558,7 +1558,6 @@ static struct clk_rcg sdc1_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1607,7 +1606,6 @@ static struct clk_rcg sdc2_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1656,7 +1654,6 @@ static struct clk_rcg sdc3_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1705,7 +1702,6 @@ static struct clk_rcg sdc4_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1754,7 +1750,6 @@ static struct clk_rcg sdc5_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c
|
||||
index eb551c75fba6a..fd495e0471bb4 100644
|
||||
--- a/drivers/clk/qcom/gcc-msm8960.c
|
||||
+++ b/drivers/clk/qcom/gcc-msm8960.c
|
||||
@@ -1628,7 +1628,6 @@ static struct clk_rcg sdc1_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1677,7 +1676,6 @@ static struct clk_rcg sdc2_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1726,7 +1724,6 @@ static struct clk_rcg sdc3_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1775,7 +1772,6 @@ static struct clk_rcg sdc4_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -1824,7 +1820,6 @@ static struct clk_rcg sdc5_src = {
|
||||
.parent_names = gcc_pxo_pll8,
|
||||
.num_parents = 2,
|
||||
.ops = &clk_rcg_ops,
|
||||
- .flags = CLK_SET_RATE_GATE,
|
||||
},
|
||||
}
|
||||
};
|
@ -0,0 +1,70 @@
|
||||
From b2ae7fbfe34642d87aeac299d9cec8f1e01ed0b2 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 1 Dec 2017 22:51:58 +0100
|
||||
Subject: [PATCH] clk: fix CLK_SET_RATE_GATE with clock rate protection
|
||||
|
||||
CLK_SET_RATE_GATE should prevent any operation which may result in a rate
|
||||
change or glitch while the clock is prepared/enabled.
|
||||
|
||||
IOW, the following sequence is not allowed anymore with CLK_SET_RATE_GATE:
|
||||
* clk_get()
|
||||
* clk_prepare_enable()
|
||||
* clk_get_rate()
|
||||
* clk_set_rate()
|
||||
|
||||
At the moment this is enforced on the leaf clock of the operation, not
|
||||
along the tree. This problematic because, if a PLL has the CLK_RATE_GATE,
|
||||
it won't be enforced if the clk_set_rate() is called on its child clocks.
|
||||
|
||||
Using clock rate protection, we can now enforce CLK_SET_RATE_GATE along the
|
||||
clock tree
|
||||
|
||||
Acked-by: Linus Walleij <linus.walleij@linaro.org>
|
||||
Tested-by: Quentin Schulz <quentin.schulz@free-electrons.com>
|
||||
Tested-by: Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 16 +++++++++++++---
|
||||
1 file changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index 9760b526ca31d..97c09243fb21c 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -691,6 +691,9 @@ static void clk_core_unprepare(struct clk_core *core)
|
||||
"Unpreparing critical %s\n", core->name))
|
||||
return;
|
||||
|
||||
+ if (core->flags & CLK_SET_RATE_GATE)
|
||||
+ clk_core_rate_unprotect(core);
|
||||
+
|
||||
if (--core->prepare_count > 0)
|
||||
return;
|
||||
|
||||
@@ -765,6 +768,16 @@ static int clk_core_prepare(struct clk_core *core)
|
||||
|
||||
core->prepare_count++;
|
||||
|
||||
+ /*
|
||||
+ * CLK_SET_RATE_GATE is a special case of clock protection
|
||||
+ * Instead of a consumer claiming exclusive rate control, it is
|
||||
+ * actually the provider which prevents any consumer from making any
|
||||
+ * operation which could result in a rate change or rate glitch while
|
||||
+ * the clock is prepared.
|
||||
+ */
|
||||
+ if (core->flags & CLK_SET_RATE_GATE)
|
||||
+ clk_core_rate_protect(core);
|
||||
+
|
||||
return 0;
|
||||
unprepare:
|
||||
clk_core_unprepare(core->parent);
|
||||
@@ -1888,9 +1901,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
if (clk_core_rate_is_protected(core))
|
||||
return -EBUSY;
|
||||
|
||||
- if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
|
||||
- return -EBUSY;
|
||||
-
|
||||
/* calculate new rates and get the topmost changed clock */
|
||||
top = clk_calc_new_rates(core, req_rate);
|
||||
if (!top)
|
@ -0,0 +1,29 @@
|
||||
From df17d1808dd4899a9469e4e7f2d9b1120b7fc208 Mon Sep 17 00:00:00 2001
|
||||
From: Sean Young <sean@mess.org>
|
||||
Date: Tue, 19 Jun 2018 13:50:36 +0100
|
||||
Subject: [PATCH] media: rc: meson: rc rc0: two consecutive events of type
|
||||
space
|
||||
|
||||
The meson generates one edge per interrupt. The duration is encoded in 12
|
||||
bits of 10 microseconds, so it can only encoding a maximum of 40
|
||||
milliseconds. As a result, it can produce multiple space events.
|
||||
|
||||
Signed-off-by: Sean Young <sean@mess.org>
|
||||
---
|
||||
drivers/media/rc/meson-ir.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
|
||||
index f449b35d25e73..9747426719b29 100644
|
||||
--- a/drivers/media/rc/meson-ir.c
|
||||
+++ b/drivers/media/rc/meson-ir.c
|
||||
@@ -97,7 +97,8 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
|
||||
status = readl_relaxed(ir->reg + IR_DEC_STATUS);
|
||||
rawir.pulse = !!(status & STATUS_IR_DEC_IN);
|
||||
|
||||
- ir_raw_event_store_with_timeout(ir->rc, &rawir);
|
||||
+ if (ir_raw_event_store_with_filter(ir->rc, &rawir))
|
||||
+ ir_raw_event_handle(ir->rc);
|
||||
|
||||
spin_unlock(&ir->lock);
|
||||
|
@ -0,0 +1,461 @@
|
||||
From 28d675fabd5e66be0ccc3cba655de36c7625f4a5 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 20 Apr 2018 23:11:41 +0200
|
||||
Subject: [PATCH] clk: add duty cycle support
|
||||
|
||||
Add the possibility to apply and query the clock signal duty cycle ratio.
|
||||
|
||||
This is useful when the duty cycle of the clock signal depends on some
|
||||
other parameters controlled by the clock framework.
|
||||
|
||||
For example, the duty cycle of a divider may depends on the raw divider
|
||||
setting (ratio = N / div) , which is controlled by the CCF. In such case,
|
||||
going through the pwm framework to control the duty cycle ratio of this
|
||||
clock would be a burden.
|
||||
|
||||
A clock provider is not required to implement the operation to set and get
|
||||
the duty cycle. If it does not implement .get_duty_cycle(), the ratio is
|
||||
assumed to be 50%.
|
||||
|
||||
This change also adds a new flag, CLK_DUTY_CYCLE_PARENT. This flag should
|
||||
be used to indicate that a clock, such as gates and muxes, may inherit
|
||||
the duty cycle ratio of its parent clock. If a clock does not provide a
|
||||
get_duty_cycle() callback and has CLK_DUTY_CYCLE_PARENT, then the call
|
||||
will be directly forwarded to its parent clock, if any. For
|
||||
set_duty_cycle(), the clock should also have CLK_SET_RATE_PARENT for the
|
||||
call to be forwarded
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 199 ++++++++++++++++++++++++++++++++++-
|
||||
include/linux/clk-provider.h | 26 +++++
|
||||
include/linux/clk.h | 33 ++++++
|
||||
include/trace/events/clk.h | 36 +++++++
|
||||
4 files changed, 289 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index 97c09243fb21c..e108f591d84a9 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -68,6 +68,7 @@ struct clk_core {
|
||||
unsigned long max_rate;
|
||||
unsigned long accuracy;
|
||||
int phase;
|
||||
+ struct clk_duty duty;
|
||||
struct hlist_head children;
|
||||
struct hlist_node child_node;
|
||||
struct hlist_head clks;
|
||||
@@ -2412,6 +2413,172 @@ int clk_get_phase(struct clk *clk)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_get_phase);
|
||||
|
||||
+static void clk_core_reset_duty_cycle_nolock(struct clk_core *core)
|
||||
+{
|
||||
+ /* Assume a default value of 50% */
|
||||
+ core->duty.num = 1;
|
||||
+ core->duty.den = 2;
|
||||
+}
|
||||
+
|
||||
+static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core);
|
||||
+
|
||||
+static int clk_core_update_duty_cycle_nolock(struct clk_core *core)
|
||||
+{
|
||||
+ struct clk_duty *duty = &core->duty;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (!core->ops->get_duty_cycle)
|
||||
+ return clk_core_update_duty_cycle_parent_nolock(core);
|
||||
+
|
||||
+ ret = core->ops->get_duty_cycle(core->hw, duty);
|
||||
+ if (ret)
|
||||
+ goto reset;
|
||||
+
|
||||
+ /* Don't trust the clock provider too much */
|
||||
+ if (duty->den == 0 || duty->num > duty->den) {
|
||||
+ ret = -EINVAL;
|
||||
+ goto reset;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+reset:
|
||||
+ clk_core_reset_duty_cycle_nolock(core);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int clk_core_update_duty_cycle_parent_nolock(struct clk_core *core)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (core->parent &&
|
||||
+ core->flags & CLK_DUTY_CYCLE_PARENT) {
|
||||
+ ret = clk_core_update_duty_cycle_nolock(core->parent);
|
||||
+ memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
|
||||
+ } else {
|
||||
+ clk_core_reset_duty_cycle_nolock(core);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
|
||||
+ struct clk_duty *duty);
|
||||
+
|
||||
+static int clk_core_set_duty_cycle_nolock(struct clk_core *core,
|
||||
+ struct clk_duty *duty)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ lockdep_assert_held(&prepare_lock);
|
||||
+
|
||||
+ if (clk_core_rate_is_protected(core))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
+ trace_clk_set_duty_cycle(core, duty);
|
||||
+
|
||||
+ if (!core->ops->set_duty_cycle)
|
||||
+ return clk_core_set_duty_cycle_parent_nolock(core, duty);
|
||||
+
|
||||
+ ret = core->ops->set_duty_cycle(core->hw, duty);
|
||||
+ if (!ret)
|
||||
+ memcpy(&core->duty, duty, sizeof(*duty));
|
||||
+
|
||||
+ trace_clk_set_duty_cycle_complete(core, duty);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int clk_core_set_duty_cycle_parent_nolock(struct clk_core *core,
|
||||
+ struct clk_duty *duty)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (core->parent &&
|
||||
+ core->flags & (CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT)) {
|
||||
+ ret = clk_core_set_duty_cycle_nolock(core->parent, duty);
|
||||
+ memcpy(&core->duty, &core->parent->duty, sizeof(core->duty));
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
|
||||
+ * @clk: clock signal source
|
||||
+ * @num: numerator of the duty cycle ratio to be applied
|
||||
+ * @den: denominator of the duty cycle ratio to be applied
|
||||
+ *
|
||||
+ * Apply the duty cycle ratio if the ratio is valid and the clock can
|
||||
+ * perform this operation
|
||||
+ *
|
||||
+ * Returns (0) on success, a negative errno otherwise.
|
||||
+ */
|
||||
+int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct clk_duty duty;
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* sanity check the ratio */
|
||||
+ if (den == 0 || num > den)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ duty.num = num;
|
||||
+ duty.den = den;
|
||||
+
|
||||
+ clk_prepare_lock();
|
||||
+
|
||||
+ if (clk->exclusive_count)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
+ ret = clk_core_set_duty_cycle_nolock(clk->core, &duty);
|
||||
+
|
||||
+ if (clk->exclusive_count)
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+
|
||||
+ clk_prepare_unlock();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_set_duty_cycle);
|
||||
+
|
||||
+static int clk_core_get_scaled_duty_cycle(struct clk_core *core,
|
||||
+ unsigned int scale)
|
||||
+{
|
||||
+ struct clk_duty *duty = &core->duty;
|
||||
+ int ret;
|
||||
+
|
||||
+ clk_prepare_lock();
|
||||
+
|
||||
+ ret = clk_core_update_duty_cycle_nolock(core);
|
||||
+ if (!ret)
|
||||
+ ret = mult_frac(scale, duty->num, duty->den);
|
||||
+
|
||||
+ clk_prepare_unlock();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal
|
||||
+ * @clk: clock signal source
|
||||
+ * @scale: scaling factor to be applied to represent the ratio as an integer
|
||||
+ *
|
||||
+ * Returns the duty cycle ratio of a clock node multiplied by the provided
|
||||
+ * scaling factor, or negative errno on error.
|
||||
+ */
|
||||
+int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale)
|
||||
+{
|
||||
+ if (!clk)
|
||||
+ return 0;
|
||||
+
|
||||
+ return clk_core_get_scaled_duty_cycle(clk->core, scale);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_get_scaled_duty_cycle);
|
||||
+
|
||||
/**
|
||||
* clk_is_match - check if two clk's point to the same hardware clock
|
||||
* @p: clk compared against q
|
||||
@@ -2465,12 +2632,13 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
- seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n",
|
||||
+ seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %5d %6d\n",
|
||||
level * 3 + 1, "",
|
||||
30 - level * 3, c->name,
|
||||
c->enable_count, c->prepare_count, c->protect_count,
|
||||
clk_core_get_rate(c), clk_core_get_accuracy(c),
|
||||
- clk_core_get_phase(c));
|
||||
+ clk_core_get_phase(c),
|
||||
+ clk_core_get_scaled_duty_cycle(c, 100000));
|
||||
}
|
||||
|
||||
static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
|
||||
@@ -2492,9 +2660,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
||||
struct clk_core *c;
|
||||
struct hlist_head **lists = (struct hlist_head **)s->private;
|
||||
|
||||
- seq_puts(s, " enable prepare protect \n");
|
||||
- seq_puts(s, " clock count count count rate accuracy phase\n");
|
||||
- seq_puts(s, "----------------------------------------------------------------------------------------\n");
|
||||
+ seq_puts(s, " enable prepare protect duty\n");
|
||||
+ seq_puts(s, " clock count count count rate accuracy phase cycle\n");
|
||||
+ seq_puts(s, "---------------------------------------------------------------------------------------------\n");
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
@@ -2521,6 +2689,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
|
||||
seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
|
||||
seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
|
||||
seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
|
||||
+ seq_printf(s, "\"duty_cycle\": %u",
|
||||
+ clk_core_get_scaled_duty_cycle(c, 100000));
|
||||
}
|
||||
|
||||
static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
|
||||
@@ -2582,6 +2752,7 @@ static const struct {
|
||||
ENTRY(CLK_SET_RATE_UNGATE),
|
||||
ENTRY(CLK_IS_CRITICAL),
|
||||
ENTRY(CLK_OPS_PARENT_ENABLE),
|
||||
+ ENTRY(CLK_DUTY_CYCLE_PARENT),
|
||||
#undef ENTRY
|
||||
};
|
||||
|
||||
@@ -2620,6 +2791,17 @@ static int possible_parents_show(struct seq_file *s, void *data)
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(possible_parents);
|
||||
|
||||
+static int clk_duty_cycle_show(struct seq_file *s, void *data)
|
||||
+{
|
||||
+ struct clk_core *core = s->private;
|
||||
+ struct clk_duty *duty = &core->duty;
|
||||
+
|
||||
+ seq_printf(s, "%u/%u\n", duty->num, duty->den);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+DEFINE_SHOW_ATTRIBUTE(clk_duty_cycle);
|
||||
+
|
||||
static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
{
|
||||
struct dentry *root;
|
||||
@@ -2638,6 +2820,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
|
||||
debugfs_create_u32("clk_protect_count", 0444, root, &core->protect_count);
|
||||
debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
|
||||
+ debugfs_create_file("clk_duty_cycle", 0444, root, core,
|
||||
+ &clk_duty_cycle_fops);
|
||||
|
||||
if (core->num_parents > 1)
|
||||
debugfs_create_file("clk_possible_parents", 0444, root, core,
|
||||
@@ -2855,6 +3039,11 @@ static int __clk_core_init(struct clk_core *core)
|
||||
else
|
||||
core->phase = 0;
|
||||
|
||||
+ /*
|
||||
+ * Set clk's duty cycle.
|
||||
+ */
|
||||
+ clk_core_update_duty_cycle_nolock(core);
|
||||
+
|
||||
/*
|
||||
* Set clk's rate. The preferred method is to use .recalc_rate. For
|
||||
* simple clocks and lazy developers the default fallback is to use the
|
||||
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
|
||||
index b7cfa037e593e..08b1aa70a38d3 100644
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -38,6 +38,8 @@
|
||||
#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
|
||||
/* parents need enable during gate/ungate, set rate and re-parent */
|
||||
#define CLK_OPS_PARENT_ENABLE BIT(12)
|
||||
+/* duty cycle call may be forwarded to the parent clock */
|
||||
+#define CLK_DUTY_CYCLE_PARENT BIT(13)
|
||||
|
||||
struct clk;
|
||||
struct clk_hw;
|
||||
@@ -66,6 +68,17 @@ struct clk_rate_request {
|
||||
struct clk_hw *best_parent_hw;
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * struct clk_duty - Struture encoding the duty cycle ratio of a clock
|
||||
+ *
|
||||
+ * @num: Numerator of the duty cycle ratio
|
||||
+ * @den: Denominator of the duty cycle ratio
|
||||
+ */
|
||||
+struct clk_duty {
|
||||
+ unsigned int num;
|
||||
+ unsigned int den;
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct clk_ops - Callback operations for hardware clocks; these are to
|
||||
* be provided by the clock implementation, and will be called by drivers
|
||||
@@ -169,6 +182,15 @@ struct clk_rate_request {
|
||||
* by the second argument. Valid values for degrees are
|
||||
* 0-359. Return 0 on success, otherwise -EERROR.
|
||||
*
|
||||
+ * @get_duty_cycle: Queries the hardware to get the current duty cycle ratio
|
||||
+ * of a clock. Returned values denominator cannot be 0 and must be
|
||||
+ * superior or equal to the numerator.
|
||||
+ *
|
||||
+ * @set_duty_cycle: Apply the duty cycle ratio to this clock signal specified by
|
||||
+ * the numerator (2nd argurment) and denominator (3rd argument).
|
||||
+ * Argument must be a valid ratio (denominator > 0
|
||||
+ * and >= numerator) Return 0 on success, otherwise -EERROR.
|
||||
+ *
|
||||
* @init: Perform platform-specific initialization magic.
|
||||
* This is not not used by any of the basic clock types.
|
||||
* Please consider other ways of solving initialization problems
|
||||
@@ -218,6 +240,10 @@ struct clk_ops {
|
||||
unsigned long parent_accuracy);
|
||||
int (*get_phase)(struct clk_hw *hw);
|
||||
int (*set_phase)(struct clk_hw *hw, int degrees);
|
||||
+ int (*get_duty_cycle)(struct clk_hw *hw,
|
||||
+ struct clk_duty *duty);
|
||||
+ int (*set_duty_cycle)(struct clk_hw *hw,
|
||||
+ struct clk_duty *duty);
|
||||
void (*init)(struct clk_hw *hw);
|
||||
void (*debug_init)(struct clk_hw *hw, struct dentry *dentry);
|
||||
};
|
||||
diff --git a/include/linux/clk.h b/include/linux/clk.h
|
||||
index 0dbd0885b2c23..4f750c481b82b 100644
|
||||
--- a/include/linux/clk.h
|
||||
+++ b/include/linux/clk.h
|
||||
@@ -141,6 +141,27 @@ int clk_set_phase(struct clk *clk, int degrees);
|
||||
*/
|
||||
int clk_get_phase(struct clk *clk);
|
||||
|
||||
+/**
|
||||
+ * clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
|
||||
+ * @clk: clock signal source
|
||||
+ * @num: numerator of the duty cycle ratio to be applied
|
||||
+ * @den: denominator of the duty cycle ratio to be applied
|
||||
+ *
|
||||
+ * Adjust the duty cycle of a clock signal by the specified ratio. Returns 0 on
|
||||
+ * success, -EERROR otherwise.
|
||||
+ */
|
||||
+int clk_set_duty_cycle(struct clk *clk, unsigned int num, unsigned int den);
|
||||
+
|
||||
+/**
|
||||
+ * clk_get_duty_cycle - return the duty cycle ratio of a clock signal
|
||||
+ * @clk: clock signal source
|
||||
+ * @scale: scaling factor to be applied to represent the ratio as an integer
|
||||
+ *
|
||||
+ * Returns the duty cycle ratio multiplied by the scale provided, otherwise
|
||||
+ * returns -EERROR.
|
||||
+ */
|
||||
+int clk_get_scaled_duty_cycle(struct clk *clk, unsigned int scale);
|
||||
+
|
||||
/**
|
||||
* clk_is_match - check if two clk's point to the same hardware clock
|
||||
* @p: clk compared against q
|
||||
@@ -183,6 +204,18 @@ static inline long clk_get_phase(struct clk *clk)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
+static inline int clk_set_duty_cycle(struct clk *clk, unsigned int num,
|
||||
+ unsigned int den)
|
||||
+{
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+
|
||||
+static inline unsigned int clk_get_scaled_duty_cycle(struct clk *clk,
|
||||
+ unsigned int scale)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline bool clk_is_match(const struct clk *p, const struct clk *q)
|
||||
{
|
||||
return p == q;
|
||||
diff --git a/include/trace/events/clk.h b/include/trace/events/clk.h
|
||||
index 2cd449328aee3..9004ffff7f326 100644
|
||||
--- a/include/trace/events/clk.h
|
||||
+++ b/include/trace/events/clk.h
|
||||
@@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete,
|
||||
TP_ARGS(core, phase)
|
||||
);
|
||||
|
||||
+DECLARE_EVENT_CLASS(clk_duty_cycle,
|
||||
+
|
||||
+ TP_PROTO(struct clk_core *core, struct clk_duty *duty),
|
||||
+
|
||||
+ TP_ARGS(core, duty),
|
||||
+
|
||||
+ TP_STRUCT__entry(
|
||||
+ __string( name, core->name )
|
||||
+ __field( unsigned int, num )
|
||||
+ __field( unsigned int, den )
|
||||
+ ),
|
||||
+
|
||||
+ TP_fast_assign(
|
||||
+ __assign_str(name, core->name);
|
||||
+ __entry->num = duty->num;
|
||||
+ __entry->den = duty->den;
|
||||
+ ),
|
||||
+
|
||||
+ TP_printk("%s %u/%u", __get_str(name), (unsigned int)__entry->num,
|
||||
+ (unsigned int)__entry->den)
|
||||
+);
|
||||
+
|
||||
+DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle,
|
||||
+
|
||||
+ TP_PROTO(struct clk_core *core, struct clk_duty *duty),
|
||||
+
|
||||
+ TP_ARGS(core, duty)
|
||||
+);
|
||||
+
|
||||
+DEFINE_EVENT(clk_duty_cycle, clk_set_duty_cycle_complete,
|
||||
+
|
||||
+ TP_PROTO(struct clk_core *core, struct clk_duty *duty),
|
||||
+
|
||||
+ TP_ARGS(core, duty)
|
||||
+);
|
||||
+
|
||||
#endif /* _TRACE_CLK_H */
|
||||
|
||||
/* This part must be outside protection */
|
@ -0,0 +1,142 @@
|
||||
From c46829185836ce19b9b14ee301d891e3f67fbe3d Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 10 Jan 2018 17:05:57 +0100
|
||||
Subject: [PATCH] clk: meson: remove obsolete register access
|
||||
|
||||
The legacy method to access the hhi register space is not longer used.
|
||||
We can safely drop it now.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/meson/axg.c | 37 ++-----------------------------------
|
||||
drivers/clk/meson/gxbb.c | 36 ++----------------------------------
|
||||
2 files changed, 4 insertions(+), 69 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c
|
||||
index bd4dbc696b88f..3fb884db1b10f 100644
|
||||
--- a/drivers/clk/meson/axg.c
|
||||
+++ b/drivers/clk/meson/axg.c
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/init.h>
|
||||
-#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -995,49 +994,17 @@ static const struct of_device_id clkc_match_table[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
-static const struct regmap_config clkc_regmap_config = {
|
||||
- .reg_bits = 32,
|
||||
- .val_bits = 32,
|
||||
- .reg_stride = 4,
|
||||
-};
|
||||
-
|
||||
static int axg_clkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
- struct resource *res;
|
||||
- void __iomem *clk_base = NULL;
|
||||
struct regmap *map;
|
||||
int ret, i;
|
||||
|
||||
/* Get the hhi system controller node if available */
|
||||
map = syscon_node_to_regmap(of_get_parent(dev->of_node));
|
||||
if (IS_ERR(map)) {
|
||||
- dev_err(dev,
|
||||
- "failed to get HHI regmap - Trying obsolete regs\n");
|
||||
-
|
||||
- /*
|
||||
- * FIXME: HHI registers should be accessed through
|
||||
- * the appropriate system controller. This is required because
|
||||
- * there is more than just clocks in this register space
|
||||
- *
|
||||
- * This fallback method is only provided temporarily until
|
||||
- * all the platform DTs are properly using the syscon node
|
||||
- */
|
||||
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
- if (!res)
|
||||
- return -EINVAL;
|
||||
-
|
||||
-
|
||||
- clk_base = devm_ioremap(dev, res->start, resource_size(res));
|
||||
- if (!clk_base) {
|
||||
- dev_err(dev, "Unable to map clk base\n");
|
||||
- return -ENXIO;
|
||||
- }
|
||||
-
|
||||
- map = devm_regmap_init_mmio(dev, clk_base,
|
||||
- &clkc_regmap_config);
|
||||
- if (IS_ERR(map))
|
||||
- return PTR_ERR(map);
|
||||
+ dev_err(dev, "failed to get HHI regmap\n");
|
||||
+ return PTR_ERR(map);
|
||||
}
|
||||
|
||||
/* Populate regmap for the regmap backed clocks */
|
||||
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
||||
index 177fffb9ebefe..297ebc3914750 100644
|
||||
--- a/drivers/clk/meson/gxbb.c
|
||||
+++ b/drivers/clk/meson/gxbb.c
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/init.h>
|
||||
-#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -2228,17 +2227,9 @@ static const struct of_device_id clkc_match_table[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
-static const struct regmap_config clkc_regmap_config = {
|
||||
- .reg_bits = 32,
|
||||
- .val_bits = 32,
|
||||
- .reg_stride = 4,
|
||||
-};
|
||||
-
|
||||
static int gxbb_clkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct clkc_data *clkc_data;
|
||||
- struct resource *res;
|
||||
- void __iomem *clk_base;
|
||||
struct regmap *map;
|
||||
int ret, i;
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -2250,31 +2241,8 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
|
||||
/* Get the hhi system controller node if available */
|
||||
map = syscon_node_to_regmap(of_get_parent(dev->of_node));
|
||||
if (IS_ERR(map)) {
|
||||
- dev_err(dev,
|
||||
- "failed to get HHI regmap - Trying obsolete regs\n");
|
||||
-
|
||||
- /*
|
||||
- * FIXME: HHI registers should be accessed through
|
||||
- * the appropriate system controller. This is required because
|
||||
- * there is more than just clocks in this register space
|
||||
- *
|
||||
- * This fallback method is only provided temporarily until
|
||||
- * all the platform DTs are properly using the syscon node
|
||||
- */
|
||||
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
- if (!res)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- clk_base = devm_ioremap(dev, res->start, resource_size(res));
|
||||
- if (!clk_base) {
|
||||
- dev_err(dev, "Unable to map clk base\n");
|
||||
- return -ENXIO;
|
||||
- }
|
||||
-
|
||||
- map = devm_regmap_init_mmio(dev, clk_base,
|
||||
- &clkc_regmap_config);
|
||||
- if (IS_ERR(map))
|
||||
- return PTR_ERR(map);
|
||||
+ dev_err(dev, "failed to get HHI regmap\n");
|
||||
+ return PTR_ERR(map);
|
||||
}
|
||||
|
||||
/* Populate regmap for the common regmap backed clocks */
|
@ -0,0 +1,51 @@
|
||||
From baa2bf58a7e8c243b89fe2de4a20784ddcbd6403 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 19 Jun 2018 18:06:30 +0200
|
||||
Subject: [PATCH] clk: meson: stop rate propagation for audio clocks
|
||||
|
||||
It is actually a lot easier and precise to setup the PLL with
|
||||
carefully chosen rates than relying on CCF clock propagation for
|
||||
this use case.
|
||||
|
||||
For this, we stop the rate propagation at the mux picking the
|
||||
PLL and let it round to the closest matching PLL
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
---
|
||||
drivers/clk/meson/gxbb.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
||||
index 297ebc3914750..7d4a4e597385c 100644
|
||||
--- a/drivers/clk/meson/gxbb.c
|
||||
+++ b/drivers/clk/meson/gxbb.c
|
||||
@@ -970,13 +970,13 @@ static struct clk_regmap gxbb_cts_amclk_sel = {
|
||||
.mask = 0x3,
|
||||
.shift = 9,
|
||||
.table = (u32[]){ 1, 2, 3 },
|
||||
+ .flags = CLK_MUX_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "cts_amclk_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
|
||||
.num_parents = 3,
|
||||
- .flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1018,13 +1018,13 @@ static struct clk_regmap gxbb_cts_mclk_i958_sel = {
|
||||
.mask = 0x3,
|
||||
.shift = 25,
|
||||
.table = (u32[]){ 1, 2, 3 },
|
||||
+ .flags = CLK_MUX_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "cts_mclk_i958_sel",
|
||||
.ops = &clk_regmap_mux_ops,
|
||||
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
|
||||
.num_parents = 3,
|
||||
- .flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
@ -0,0 +1,13 @@
|
||||
--- a/sound/soc/codecs/Kconfig 2018-09-25 02:40:11.206734417 +0200
|
||||
+++ b/sound/soc/codecs/Kconfig 2018-09-25 03:32:51.395650591 +0200
|
||||
@@ -747,7 +747,9 @@
|
||||
select REGMAP_SPI
|
||||
|
||||
config SND_SOC_PCM5102A
|
||||
- tristate
|
||||
+ tristate "PCM5102A Simple driver"
|
||||
+ default m if SND_SOC_MESON=m
|
||||
+ default y if SND_SOC_MESON=y
|
||||
|
||||
config SND_SOC_PCM512x
|
||||
tristate
|
@ -0,0 +1,68 @@
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-09-25 02:40:03.744549370 +0200
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-09-25 03:42:03.505596966 +0200
|
||||
@@ -147,10 +147,27 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ i2s_codec: external-codec {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "ti,pcm5102a";
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "meson-gx-audio";
|
||||
|
||||
+ simple-audio-card,widgets =
|
||||
+ "Line", "Analog Left Output",
|
||||
+ "Line", "Analog Right Output";
|
||||
+ simple-audio-card,routing =
|
||||
+ "Analog Left Output", "OUTL",
|
||||
+ "Analog Right Output", "OUTR",
|
||||
+ "INL", "AOUTL",
|
||||
+ "INR", "AOUTR";
|
||||
+
|
||||
+ status = "okay";
|
||||
+
|
||||
assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
<&clkc CLKID_MPLL0>,
|
||||
<&clkc CLKID_MPLL1>;
|
||||
@@ -178,6 +195,27 @@
|
||||
sound-dai = <&hdmi_tx>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+ simple-audio-card,dai-link@1 {
|
||||
+ /* I2C external codec Output */
|
||||
+ format = "i2s";
|
||||
+ bitclock-inversion;
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&i2s_codec>;
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -264,6 +302,9 @@
|
||||
|
||||
&i2s_dai {
|
||||
status = "okay";
|
||||
+ pinctrl-0 = <&i2s_am_clk_pins>, <&i2s_out_ao_clk_pins>,
|
||||
+ <&i2s_out_lr_clk_pins>, <&i2s_out_ch01_ao_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&ir {
|
@ -0,0 +1,51 @@
|
||||
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-04-28 19:24:56.090524456 +0200
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-04-29 23:09:48.559371108 +0200
|
||||
@@ -409,6 +409,7 @@
|
||||
&usb0_phy {
|
||||
status = "okay";
|
||||
phy-supply = <&usb_otg_pwr>;
|
||||
+ dr_mode = "otg";
|
||||
};
|
||||
|
||||
&usb1_phy {
|
||||
@@ -418,6 +419,7 @@
|
||||
|
||||
&usb0 {
|
||||
status = "okay";
|
||||
+ dr_mode = "host";
|
||||
};
|
||||
|
||||
&usb1 {
|
||||
|
||||
--- a/drivers/phy/amlogic/phy-meson8b-usb2.c 2018-04-28 19:22:57.420144229 +0200
|
||||
+++ b/drivers/phy/amlogic/phy-meson8b-usb2.c 2018-04-29 23:13:57.136515043 +0200
|
||||
@@ -113,6 +113,7 @@
|
||||
struct phy_meson8b_usb2_priv {
|
||||
void __iomem *regs;
|
||||
enum usb_dr_mode dr_mode;
|
||||
+ enum usb_dr_mode phy_mode;
|
||||
struct clk *clk_usb_general;
|
||||
struct clk *clk_usb;
|
||||
struct reset_control *reset;
|
||||
@@ -181,7 +182,7 @@
|
||||
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
|
||||
REG_CTRL_SOF_TOGGLE_OUT);
|
||||
|
||||
- if (priv->dr_mode == USB_DR_MODE_HOST) {
|
||||
+ if (priv->phy_mode == USB_DR_MODE_HOST) {
|
||||
phy_meson8b_usb2_mask_bits(priv, REG_ADP_BC,
|
||||
REG_ADP_BC_ACA_ENABLE,
|
||||
REG_ADP_BC_ACA_ENABLE);
|
||||
@@ -251,6 +252,11 @@
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ priv->phy_mode = usb_get_dr_mode(&pdev->dev);
|
||||
+ if (priv->phy_mode == USB_DR_MODE_UNKNOWN) {
|
||||
+ priv->phy_mode = priv->dr_mode;
|
||||
+ }
|
||||
+
|
||||
phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(&pdev->dev, "failed to create PHY\n");
|
@ -0,0 +1,103 @@
|
||||
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
|
||||
index 674b35f40..3497cabda 100644
|
||||
--- a/drivers/mailbox/mailbox.c
|
||||
+++ b/drivers/mailbox/mailbox.c
|
||||
@@ -26,6 +26,8 @@
|
||||
static LIST_HEAD(mbox_cons);
|
||||
static DEFINE_MUTEX(con_mutex);
|
||||
|
||||
+static void poll_txdone(struct timer_list *t);
|
||||
+
|
||||
static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
|
||||
{
|
||||
int idx;
|
||||
@@ -86,8 +88,7 @@ static void msg_submit(struct mbox_chan *chan)
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
if (!err && (chan->txdone_method & TXDONE_BY_POLL))
|
||||
- /* kick start the timer immediately to avoid delays */
|
||||
- hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
|
||||
+ poll_txdone(&chan->mbox->poll);
|
||||
}
|
||||
|
||||
static void tx_tick(struct mbox_chan *chan, int r)
|
||||
@@ -114,10 +115,9 @@ static void tx_tick(struct mbox_chan *chan, int r)
|
||||
complete(&chan->tx_complete);
|
||||
}
|
||||
|
||||
-static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
||||
+static void poll_txdone(struct timer_list *t)
|
||||
{
|
||||
- struct mbox_controller *mbox =
|
||||
- container_of(hrtimer, struct mbox_controller, poll_hrt);
|
||||
+ struct mbox_controller *mbox = from_timer(mbox, t, poll);
|
||||
bool txdone, resched = false;
|
||||
int i;
|
||||
|
||||
@@ -133,11 +133,9 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
||||
}
|
||||
}
|
||||
|
||||
- if (resched) {
|
||||
- hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
|
||||
- return HRTIMER_RESTART;
|
||||
- }
|
||||
- return HRTIMER_NORESTART;
|
||||
+ if (resched)
|
||||
+ mod_timer(&mbox->poll, jiffies +
|
||||
+ msecs_to_jiffies(mbox->txpoll_period));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,9 +464,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC,
|
||||
- HRTIMER_MODE_REL);
|
||||
- mbox->poll_hrt.function = txdone_hrtimer;
|
||||
+ timer_setup(&mbox->poll, &poll_txdone, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < mbox->num_chans; i++) {
|
||||
@@ -510,7 +506,7 @@ void mbox_controller_unregister(struct mbox_controller *mbox)
|
||||
mbox_free_channel(&mbox->chans[i]);
|
||||
|
||||
if (mbox->txdone_poll)
|
||||
- hrtimer_cancel(&mbox->poll_hrt);
|
||||
+ del_timer_sync(&mbox->poll);
|
||||
|
||||
mutex_unlock(&con_mutex);
|
||||
}
|
||||
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
|
||||
index 74deadb42..68c424544 100644
|
||||
--- a/include/linux/mailbox_controller.h
|
||||
+++ b/include/linux/mailbox_controller.h
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
-#include <linux/hrtimer.h>
|
||||
+#include <linux/timer.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
@@ -67,8 +67,7 @@ struct mbox_chan_ops {
|
||||
* @txpoll_period: If 'txdone_poll' is in effect, the API polls for
|
||||
* last TX's status after these many millisecs
|
||||
* @of_xlate: Controller driver specific mapping of channel via DT
|
||||
- * @poll_hrt: API private. hrtimer used to poll for TXDONE on all
|
||||
- * channels.
|
||||
+ * @poll: API private. Used to poll for TXDONE on all channels.
|
||||
* @node: API private. To hook into list of controllers.
|
||||
*/
|
||||
struct mbox_controller {
|
||||
@@ -82,7 +81,7 @@ struct mbox_controller {
|
||||
struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
|
||||
const struct of_phandle_args *sp);
|
||||
/* Internal to API */
|
||||
- struct hrtimer poll_hrt;
|
||||
+ struct timer_list poll;
|
||||
struct list_head node;
|
||||
};
|
||||
|
@ -0,0 +1,714 @@
|
||||
From 2d49cff77c34c63ae5aa32537cc5fef1ea2e165d Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 27 Apr 2018 17:19:46 +0200
|
||||
Subject: [PATCH] drm/meson: Make DMT timings parameter generic and add more
|
||||
frequencies
|
||||
|
||||
Add more frequencies to support more timings with the generic timings
|
||||
parameters calculation.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/gpu/drm/meson/meson_dw_hdmi.c | 10 +-
|
||||
drivers/gpu/drm/meson/meson_vclk.c | 184 ++++++++++++++++++-
|
||||
drivers/gpu/drm/meson/meson_venc.c | 330 +++++-----------------------------
|
||||
drivers/gpu/drm/meson/meson_venc.h | 3 +-
|
||||
4 files changed, 231 insertions(+), 296 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
index a393095aac1a6..7ebfef86383fe 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
@@ -546,6 +546,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
unsigned int venc_freq;
|
||||
unsigned int hdmi_freq;
|
||||
int vic = drm_match_cea_mode(mode);
|
||||
+ enum drm_mode_status status;
|
||||
|
||||
DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
@@ -556,8 +557,9 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
|
||||
/* Check against non-VIC supported modes */
|
||||
if (!vic) {
|
||||
- if (!meson_venc_hdmi_supported_mode(mode))
|
||||
- return MODE_BAD;
|
||||
+ status = meson_venc_hdmi_supported_mode(mode);
|
||||
+ if (status != MODE_OK)
|
||||
+ return status;
|
||||
/* Check against supported VIC modes */
|
||||
} else if (!meson_venc_hdmi_supported_vic(vic))
|
||||
return MODE_BAD;
|
||||
@@ -587,6 +589,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
|
||||
switch (vclk_freq) {
|
||||
case 25175:
|
||||
case 40000:
|
||||
+ case 32000:
|
||||
+ case 36000:
|
||||
+ case 33750:
|
||||
+ case 33900:
|
||||
case 54000:
|
||||
case 65000:
|
||||
case 74250:
|
||||
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
index f0511220317f9..86975f245c361 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
@@ -330,22 +330,30 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
|
||||
#define MESON_VCLK_HDMI_DDR_148500 3
|
||||
/* 4028 /4 /4 /1 /5 /2 => /1 /1 */
|
||||
#define MESON_VCLK_HDMI_25175 4
|
||||
+/* 2560 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+#define MESON_VCLK_HDMI_32000 5
|
||||
+/* 2700 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+#define MESON_VCLK_HDMI_33750 6
|
||||
+/* 2712 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+#define MESON_VCLK_HDMI_33900 7
|
||||
+/* 2880 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+#define MESON_VCLK_HDMI_36000 8
|
||||
/* 3200 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_40000 5
|
||||
+#define MESON_VCLK_HDMI_40000 9
|
||||
/* 5200 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_65000 6
|
||||
+#define MESON_VCLK_HDMI_65000 10
|
||||
/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_74250 7
|
||||
+#define MESON_VCLK_HDMI_74250 11
|
||||
/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_108000 8
|
||||
+#define MESON_VCLK_HDMI_108000 12
|
||||
/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_148500 9
|
||||
+#define MESON_VCLK_HDMI_148500 13
|
||||
/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_162000 10
|
||||
+#define MESON_VCLK_HDMI_162000 14
|
||||
/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_297000 11
|
||||
+#define MESON_VCLK_HDMI_297000 15
|
||||
/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_594000 12
|
||||
+#define MESON_VCLK_HDMI_594000 16
|
||||
|
||||
struct meson_vclk_params {
|
||||
unsigned int pll_base_freq;
|
||||
@@ -419,6 +427,38 @@ struct meson_vclk_params {
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 2,
|
||||
},
|
||||
+ [MESON_VCLK_HDMI_32000] = {
|
||||
+ .pll_base_freq = 2560000,
|
||||
+ .pll_od1 = 4,
|
||||
+ .pll_od2 = 2,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
+ [MESON_VCLK_HDMI_33750] = {
|
||||
+ .pll_base_freq = 2700000,
|
||||
+ .pll_od1 = 4,
|
||||
+ .pll_od2 = 2,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
+ [MESON_VCLK_HDMI_33900] = {
|
||||
+ .pll_base_freq = 2712000,
|
||||
+ .pll_od1 = 4,
|
||||
+ .pll_od2 = 2,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
+ [MESON_VCLK_HDMI_36000] = {
|
||||
+ .pll_base_freq = 2880000,
|
||||
+ .pll_od1 = 4,
|
||||
+ .pll_od2 = 2,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
[MESON_VCLK_HDMI_40000] = {
|
||||
.pll_base_freq = 3200000,
|
||||
.pll_od1 = 4,
|
||||
@@ -480,6 +520,86 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
|
||||
switch (base) {
|
||||
+ case 2560000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000235);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
+
|
||||
+ /* Enable and unreset */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ 0x7 << 28, 0x4 << 28);
|
||||
+
|
||||
+ /* Poll for lock bit */
|
||||
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+
|
||||
+ /* div_frac */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
+ 0xFFFF, 0x4555);
|
||||
+ break;
|
||||
+
|
||||
+ case 2700000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000238);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
+
|
||||
+ /* Enable and unreset */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ 0x7 << 28, 0x4 << 28);
|
||||
+
|
||||
+ /* Poll for lock bit */
|
||||
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+
|
||||
+ /* div_frac */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
+ 0xFFFF, 0x4400);
|
||||
+ break;
|
||||
+
|
||||
+ case 2712000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000238);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
+
|
||||
+ /* Enable and unreset */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ 0x7 << 28, 0x4 << 28);
|
||||
+
|
||||
+ /* Poll for lock bit */
|
||||
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+
|
||||
+ /* div_frac */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
+ 0xFFFF, 0x4800);
|
||||
+ break;
|
||||
+
|
||||
+ case 2880000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
+
|
||||
+ /* Enable and unreset */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ 0x7 << 28, 0x4 << 28);
|
||||
+
|
||||
+ /* Poll for lock bit */
|
||||
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+ break;
|
||||
+
|
||||
case 2970000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
@@ -640,6 +760,42 @@ void meson_hdmi_pll_set(struct meson_drm *priv,
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
switch (base) {
|
||||
+ case 2560000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000026a);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
+ break;
|
||||
+
|
||||
+ case 2700000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000270);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
+ break;
|
||||
+
|
||||
+ case 2712000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000271);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
+ break;
|
||||
+
|
||||
+ case 2880000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000278);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
+ break;
|
||||
+
|
||||
case 2970000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
|
||||
@@ -789,6 +945,18 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
case 25175:
|
||||
freq = MESON_VCLK_HDMI_25175;
|
||||
break;
|
||||
+ case 32000:
|
||||
+ freq = MESON_VCLK_HDMI_32000;
|
||||
+ break;
|
||||
+ case 33750:
|
||||
+ freq = MESON_VCLK_HDMI_33750;
|
||||
+ break;
|
||||
+ case 33900:
|
||||
+ freq = MESON_VCLK_HDMI_33900;
|
||||
+ break;
|
||||
+ case 36000:
|
||||
+ freq = MESON_VCLK_HDMI_36000;
|
||||
+ break;
|
||||
case 40000:
|
||||
freq = MESON_VCLK_HDMI_40000;
|
||||
break;
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
|
||||
index 6e27013898013..ea178151399c5 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.c
|
||||
@@ -697,258 +697,6 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
|
||||
},
|
||||
};
|
||||
|
||||
-union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = {
|
||||
- .encp = {
|
||||
- .dvi_settings = 0x21,
|
||||
- .video_mode = 0x4040,
|
||||
- .video_mode_adv = 0x18,
|
||||
- /* video_prog_mode */
|
||||
- /* video_sync_mode */
|
||||
- /* video_yc_dly */
|
||||
- /* video_rgb_ctrl */
|
||||
- /* video_filt_ctrl */
|
||||
- /* video_ofld_voav_ofst */
|
||||
- /* yfp1_htime */
|
||||
- /* yfp2_htime */
|
||||
- .max_pxcnt = 0x31f,
|
||||
- /* hspuls_begin */
|
||||
- /* hspuls_end */
|
||||
- /* hspuls_switch */
|
||||
- /* vspuls_begin */
|
||||
- /* vspuls_end */
|
||||
- /* vspuls_bline */
|
||||
- /* vspuls_eline */
|
||||
- .havon_begin = 0x90,
|
||||
- .havon_end = 0x30f,
|
||||
- .vavon_bline = 0x23,
|
||||
- .vavon_eline = 0x202,
|
||||
- /* eqpuls_begin */
|
||||
- /* eqpuls_end */
|
||||
- /* eqpuls_bline */
|
||||
- /* eqpuls_eline */
|
||||
- .hso_begin = 0,
|
||||
- .hso_end = 0x60,
|
||||
- .vso_begin = 0x1e,
|
||||
- .vso_end = 0x32,
|
||||
- .vso_bline = 0,
|
||||
- .vso_eline = 2,
|
||||
- .vso_eline_present = true,
|
||||
- /* sy_val */
|
||||
- /* sy2_val */
|
||||
- .max_lncnt = 0x20c,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = {
|
||||
- .encp = {
|
||||
- .dvi_settings = 0x21,
|
||||
- .video_mode = 0x4040,
|
||||
- .video_mode_adv = 0x18,
|
||||
- /* video_prog_mode */
|
||||
- /* video_sync_mode */
|
||||
- /* video_yc_dly */
|
||||
- /* video_rgb_ctrl */
|
||||
- /* video_filt_ctrl */
|
||||
- /* video_ofld_voav_ofst */
|
||||
- /* yfp1_htime */
|
||||
- /* yfp2_htime */
|
||||
- .max_pxcnt = 0x41f,
|
||||
- /* hspuls_begin */
|
||||
- /* hspuls_end */
|
||||
- /* hspuls_switch */
|
||||
- /* vspuls_begin */
|
||||
- /* vspuls_end */
|
||||
- /* vspuls_bline */
|
||||
- /* vspuls_eline */
|
||||
- .havon_begin = 0xD8,
|
||||
- .havon_end = 0x3f7,
|
||||
- .vavon_bline = 0x1b,
|
||||
- .vavon_eline = 0x272,
|
||||
- /* eqpuls_begin */
|
||||
- /* eqpuls_end */
|
||||
- /* eqpuls_bline */
|
||||
- /* eqpuls_eline */
|
||||
- .hso_begin = 0,
|
||||
- .hso_end = 0x80,
|
||||
- .vso_begin = 0x1e,
|
||||
- .vso_end = 0x32,
|
||||
- .vso_bline = 0,
|
||||
- .vso_eline = 4,
|
||||
- .vso_eline_present = true,
|
||||
- /* sy_val */
|
||||
- /* sy2_val */
|
||||
- .max_lncnt = 0x273,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = {
|
||||
- .encp = {
|
||||
- .dvi_settings = 0x21,
|
||||
- .video_mode = 0x4040,
|
||||
- .video_mode_adv = 0x18,
|
||||
- /* video_prog_mode */
|
||||
- /* video_sync_mode */
|
||||
- /* video_yc_dly */
|
||||
- /* video_rgb_ctrl */
|
||||
- /* video_filt_ctrl */
|
||||
- /* video_ofld_voav_ofst */
|
||||
- /* yfp1_htime */
|
||||
- /* yfp2_htime */
|
||||
- .max_pxcnt = 1343,
|
||||
- /* hspuls_begin */
|
||||
- /* hspuls_end */
|
||||
- /* hspuls_switch */
|
||||
- /* vspuls_begin */
|
||||
- /* vspuls_end */
|
||||
- /* vspuls_bline */
|
||||
- /* vspuls_eline */
|
||||
- .havon_begin = 296,
|
||||
- .havon_end = 1319,
|
||||
- .vavon_bline = 35,
|
||||
- .vavon_eline = 802,
|
||||
- /* eqpuls_begin */
|
||||
- /* eqpuls_end */
|
||||
- /* eqpuls_bline */
|
||||
- /* eqpuls_eline */
|
||||
- .hso_begin = 0,
|
||||
- .hso_end = 136,
|
||||
- .vso_begin = 30,
|
||||
- .vso_end = 50,
|
||||
- .vso_bline = 0,
|
||||
- .vso_eline = 6,
|
||||
- .vso_eline_present = true,
|
||||
- /* sy_val */
|
||||
- /* sy2_val */
|
||||
- .max_lncnt = 805,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = {
|
||||
- .encp = {
|
||||
- .dvi_settings = 0x21,
|
||||
- .video_mode = 0x4040,
|
||||
- .video_mode_adv = 0x18,
|
||||
- /* video_prog_mode */
|
||||
- /* video_sync_mode */
|
||||
- /* video_yc_dly */
|
||||
- /* video_rgb_ctrl */
|
||||
- /* video_filt_ctrl */
|
||||
- /* video_ofld_voav_ofst */
|
||||
- /* yfp1_htime */
|
||||
- /* yfp2_htime */
|
||||
- .max_pxcnt = 0x63f,
|
||||
- /* hspuls_begin */
|
||||
- /* hspuls_end */
|
||||
- /* hspuls_switch */
|
||||
- /* vspuls_begin */
|
||||
- /* vspuls_end */
|
||||
- /* vspuls_bline */
|
||||
- /* vspuls_eline */
|
||||
- .havon_begin = 0x180,
|
||||
- .havon_end = 0x5ff,
|
||||
- .vavon_bline = 0x23,
|
||||
- .vavon_eline = 0x382,
|
||||
- /* eqpuls_begin */
|
||||
- /* eqpuls_end */
|
||||
- /* eqpuls_bline */
|
||||
- /* eqpuls_eline */
|
||||
- .hso_begin = 0,
|
||||
- .hso_end = 0x80,
|
||||
- .vso_begin = 0x1e,
|
||||
- .vso_end = 0x32,
|
||||
- .vso_bline = 0,
|
||||
- .vso_eline = 3,
|
||||
- .vso_eline_present = true,
|
||||
- /* sy_val */
|
||||
- /* sy2_val */
|
||||
- .max_lncnt = 0x383,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = {
|
||||
- .encp = {
|
||||
- .dvi_settings = 0x21,
|
||||
- .video_mode = 0x4040,
|
||||
- .video_mode_adv = 0x18,
|
||||
- /* video_prog_mode */
|
||||
- /* video_sync_mode */
|
||||
- /* video_yc_dly */
|
||||
- /* video_rgb_ctrl */
|
||||
- /* video_filt_ctrl */
|
||||
- /* video_ofld_voav_ofst */
|
||||
- /* yfp1_htime */
|
||||
- /* yfp2_htime */
|
||||
- .max_pxcnt = 0x697,
|
||||
- /* hspuls_begin */
|
||||
- /* hspuls_end */
|
||||
- /* hspuls_switch */
|
||||
- /* vspuls_begin */
|
||||
- /* vspuls_end */
|
||||
- /* vspuls_bline */
|
||||
- /* vspuls_eline */
|
||||
- .havon_begin = 0x168,
|
||||
- .havon_end = 0x667,
|
||||
- .vavon_bline = 0x29,
|
||||
- .vavon_eline = 0x428,
|
||||
- /* eqpuls_begin */
|
||||
- /* eqpuls_end */
|
||||
- /* eqpuls_bline */
|
||||
- /* eqpuls_eline */
|
||||
- .hso_begin = 0,
|
||||
- .hso_end = 0x70,
|
||||
- .vso_begin = 0x1e,
|
||||
- .vso_end = 0x32,
|
||||
- .vso_bline = 0,
|
||||
- .vso_eline = 3,
|
||||
- .vso_eline_present = true,
|
||||
- /* sy_val */
|
||||
- /* sy2_val */
|
||||
- .max_lncnt = 0x429,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
-union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = {
|
||||
- .encp = {
|
||||
- .dvi_settings = 0x21,
|
||||
- .video_mode = 0x4040,
|
||||
- .video_mode_adv = 0x18,
|
||||
- /* video_prog_mode */
|
||||
- /* video_sync_mode */
|
||||
- /* video_yc_dly */
|
||||
- /* video_rgb_ctrl */
|
||||
- /* video_filt_ctrl */
|
||||
- /* video_ofld_voav_ofst */
|
||||
- /* yfp1_htime */
|
||||
- /* yfp2_htime */
|
||||
- .max_pxcnt = 0x86f,
|
||||
- /* hspuls_begin */
|
||||
- /* hspuls_end */
|
||||
- /* hspuls_switch */
|
||||
- /* vspuls_begin */
|
||||
- /* vspuls_end */
|
||||
- /* vspuls_bline */
|
||||
- /* vspuls_eline */
|
||||
- .havon_begin = 0x1f0,
|
||||
- .havon_end = 0x82f,
|
||||
- .vavon_bline = 0x31,
|
||||
- .vavon_eline = 0x4e0,
|
||||
- /* eqpuls_begin */
|
||||
- /* eqpuls_end */
|
||||
- /* eqpuls_bline */
|
||||
- /* eqpuls_eline */
|
||||
- .hso_begin = 0,
|
||||
- .hso_end = 0xc0,
|
||||
- .vso_begin = 0x1e,
|
||||
- .vso_end = 0x32,
|
||||
- .vso_bline = 0,
|
||||
- .vso_eline = 3,
|
||||
- .vso_eline_present = true,
|
||||
- /* sy_val */
|
||||
- /* sy2_val */
|
||||
- .max_lncnt = 0x4e1,
|
||||
- },
|
||||
-};
|
||||
-
|
||||
struct meson_hdmi_venc_dmt_mode {
|
||||
struct drm_display_mode drm_mode;
|
||||
union meson_hdmi_venc_mode *mode;
|
||||
@@ -958,49 +706,42 @@ struct meson_hdmi_venc_dmt_mode {
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
- &meson_hdmi_encp_mode_640x480_60,
|
||||
},
|
||||
/* 800x600@60Hz */
|
||||
{
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
- &meson_hdmi_encp_mode_800x600_60,
|
||||
},
|
||||
/* 1024x768@60Hz */
|
||||
{
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024,
|
||||
1048, 1184, 1344, 0, 768, 771, 777, 806, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
- &meson_hdmi_encp_mode_1024x768_60,
|
||||
},
|
||||
/* 1152x864@75Hz */
|
||||
{
|
||||
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152,
|
||||
1216, 1344, 1600, 0, 864, 865, 868, 900, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
- &meson_hdmi_encp_mode_1152x864_75,
|
||||
},
|
||||
/* 1280x1024@60Hz */
|
||||
{
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280,
|
||||
1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
- &meson_hdmi_encp_mode_1280x1024_60,
|
||||
},
|
||||
/* 1600x1200@60Hz */
|
||||
{
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
|
||||
1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
- &meson_hdmi_encp_mode_1600x1200_60,
|
||||
},
|
||||
/* 1920x1080@60Hz */
|
||||
{
|
||||
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920,
|
||||
2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
- &meson_hdmi_encp_mode_1080p60
|
||||
},
|
||||
{ }, /* sentinel */
|
||||
};
|
||||
@@ -1044,17 +785,20 @@ static unsigned long modulo(unsigned long a, unsigned long b)
|
||||
return a;
|
||||
}
|
||||
|
||||
-bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
|
||||
+enum drm_mode_status
|
||||
+meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
|
||||
{
|
||||
- struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
|
||||
+ if (mode->flags & ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC |
|
||||
+ DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))
|
||||
+ return MODE_BAD;
|
||||
|
||||
- while (vmode->mode) {
|
||||
- if (drm_mode_equal(&vmode->drm_mode, mode))
|
||||
- return true;
|
||||
- vmode++;
|
||||
- }
|
||||
+ if (mode->hdisplay < 640 || mode->hdisplay > 1920)
|
||||
+ return MODE_BAD_HVALUE;
|
||||
|
||||
- return false;
|
||||
+ if (mode->vdisplay < 480 || mode->vdisplay > 1200)
|
||||
+ return MODE_BAD_VVALUE;
|
||||
+
|
||||
+ return MODE_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
|
||||
|
||||
@@ -1072,18 +816,29 @@ bool meson_venc_hdmi_supported_vic(int vic)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
|
||||
|
||||
-static union meson_hdmi_venc_mode
|
||||
-*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode)
|
||||
+void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode,
|
||||
+ union meson_hdmi_venc_mode *dmt_mode)
|
||||
{
|
||||
- struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
|
||||
-
|
||||
- while (vmode->mode) {
|
||||
- if (drm_mode_equal(&vmode->drm_mode, mode))
|
||||
- return vmode->mode;
|
||||
- vmode++;
|
||||
- }
|
||||
-
|
||||
- return NULL;
|
||||
+ memset(dmt_mode, 0, sizeof(*dmt_mode));
|
||||
+
|
||||
+ dmt_mode->encp.dvi_settings = 0x21;
|
||||
+ dmt_mode->encp.video_mode = 0x4040;
|
||||
+ dmt_mode->encp.video_mode_adv = 0x18;
|
||||
+ dmt_mode->encp.max_pxcnt = mode->htotal - 1;
|
||||
+ dmt_mode->encp.havon_begin = mode->htotal - mode->hsync_start;
|
||||
+ dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin +
|
||||
+ mode->hdisplay - 1;
|
||||
+ dmt_mode->encp.vavon_bline = mode->vtotal - mode->vsync_start;
|
||||
+ dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline +
|
||||
+ mode->vdisplay - 1;
|
||||
+ dmt_mode->encp.hso_begin = 0;
|
||||
+ dmt_mode->encp.hso_end = mode->hsync_end - mode->hsync_start;
|
||||
+ dmt_mode->encp.vso_begin = 30;
|
||||
+ dmt_mode->encp.vso_end = 50;
|
||||
+ dmt_mode->encp.vso_bline = 0;
|
||||
+ dmt_mode->encp.vso_eline = mode->vsync_end - mode->vsync_start;
|
||||
+ dmt_mode->encp.vso_eline_present = true;
|
||||
+ dmt_mode->encp.max_lncnt = mode->vtotal - 1;
|
||||
}
|
||||
|
||||
static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
|
||||
@@ -1120,6 +875,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
union meson_hdmi_venc_mode *vmode = NULL;
|
||||
+ union meson_hdmi_venc_mode vmode_dmt;
|
||||
bool use_enci = false;
|
||||
bool venc_repeat = false;
|
||||
bool hdmi_repeat = false;
|
||||
@@ -1147,14 +903,18 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
|
||||
unsigned int sof_lines;
|
||||
unsigned int vsync_lines;
|
||||
|
||||
- if (meson_venc_hdmi_supported_vic(vic))
|
||||
+ if (meson_venc_hdmi_supported_vic(vic)) {
|
||||
vmode = meson_venc_hdmi_get_vic_vmode(vic);
|
||||
- else
|
||||
- vmode = meson_venc_hdmi_get_dmt_vmode(mode);
|
||||
- if (!vmode) {
|
||||
- dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
|
||||
- DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode));
|
||||
- return;
|
||||
+ if (!vmode) {
|
||||
+ dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
|
||||
+ DRM_MODE_FMT "\n", __func__,
|
||||
+ DRM_MODE_ARG(mode));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ else {
|
||||
+ meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt);
|
||||
+ vmode = &vmode_dmt;
|
||||
}
|
||||
|
||||
/* Use VENCI for 480i and 576i and double HDMI pixels */
|
||||
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
|
||||
index 7c18a36a0dd0c..97eaebbfa0c4a 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.h
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.h
|
||||
@@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode {
|
||||
};
|
||||
|
||||
/* HDMI Clock parameters */
|
||||
-bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
|
||||
+enum drm_mode_status
|
||||
+meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
|
||||
bool meson_venc_hdmi_supported_vic(int vic);
|
||||
bool meson_venc_hdmi_venc_repeat(int vic);
|
||||
|
@ -0,0 +1,119 @@
|
||||
diff -ur a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.c 2018-06-02 20:21:48.000000000 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.c 2018-06-02 20:16:44.008061996 +0200
|
||||
@@ -428,9 +428,9 @@
|
||||
.vclk_div = 2,
|
||||
},
|
||||
[MESON_VCLK_HDMI_32000] = {
|
||||
- .pll_base_freq = 2560000,
|
||||
+ .pll_base_freq = 5120000,
|
||||
.pll_od1 = 4,
|
||||
- .pll_od2 = 2,
|
||||
+ .pll_od2 = 4,
|
||||
.pll_od3 = 1,
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 2,
|
||||
@@ -520,27 +520,6 @@
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
|
||||
switch (base) {
|
||||
- case 2560000:
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000235);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
-
|
||||
- /* Enable and unreset */
|
||||
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
- 0x7 << 28, 0x4 << 28);
|
||||
-
|
||||
- /* Poll for lock bit */
|
||||
- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
- val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
-
|
||||
- /* div_frac */
|
||||
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
- 0xFFFF, 0x4555);
|
||||
- break;
|
||||
-
|
||||
case 2700000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000238);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
@@ -722,6 +701,27 @@
|
||||
val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
break;
|
||||
|
||||
+ case 5120000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026a);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
+
|
||||
+ /* unreset */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ BIT(28), 0);
|
||||
+
|
||||
+ /* Poll for lock bit */
|
||||
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+
|
||||
+ /* div_frac */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
+ 0xFFFF, 0x4aab);
|
||||
+ break;
|
||||
+
|
||||
case 5940000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b);
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
@@ -760,15 +760,6 @@
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
switch (base) {
|
||||
- case 2560000:
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000026a);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
- break;
|
||||
-
|
||||
case 2700000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000270);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200);
|
||||
@@ -847,6 +838,15 @@
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
+ break;
|
||||
+
|
||||
+ case 5120000:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d5);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
break;
|
||||
|
||||
diff -ur a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.c 2018-06-02 16:39:27.777402009 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.c 2018-06-02 20:23:23.744646670 +0200
|
||||
@@ -713,6 +713,12 @@
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
},
|
||||
+ /* 1024x600@43Hz */
|
||||
+ {
|
||||
+ { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 32000, 1024,
|
||||
+ 1064, 1112, 1152, 0, 600, 613, 616, 645, 0,
|
||||
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
+ },
|
||||
/* 1024x768@60Hz */
|
||||
{
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024,
|
@ -0,0 +1,547 @@
|
||||
diff -ur a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
|
||||
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c 2018-06-02 16:39:27.777402009 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c 2018-06-02 17:25:33.803332054 +0200
|
||||
@@ -588,22 +588,28 @@
|
||||
/* Finally filter by configurable vclk frequencies */
|
||||
switch (vclk_freq) {
|
||||
case 25175:
|
||||
- case 40000:
|
||||
+ case 29750:
|
||||
case 32000:
|
||||
case 36000:
|
||||
case 33750:
|
||||
case 33900:
|
||||
+ case 40000:
|
||||
case 54000:
|
||||
case 65000:
|
||||
case 74250:
|
||||
+ case 106500:
|
||||
case 108000:
|
||||
case 148500:
|
||||
case 162000:
|
||||
+ case 193250:
|
||||
case 297000:
|
||||
case 594000:
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
+ if (meson_vclk_supported(vclk_freq))
|
||||
+ return MODE_OK;
|
||||
+
|
||||
return MODE_CLOCK_RANGE;
|
||||
}
|
||||
|
||||
diff -ur a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.c 2018-06-02 20:16:44.008061996 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.c 2018-06-04 03:26:22.092619417 +0200
|
||||
@@ -321,39 +321,49 @@
|
||||
}
|
||||
|
||||
|
||||
-/* PLL O1 O2 O3 VP DV EN TX */
|
||||
-/* 4320 /4 /4 /1 /5 /1 => /2 /2 */
|
||||
-#define MESON_VCLK_HDMI_ENCI_54000 1
|
||||
-/* 4320 /4 /4 /1 /5 /1 => /1 /2 */
|
||||
-#define MESON_VCLK_HDMI_DDR_54000 2
|
||||
-/* 2970 /4 /1 /1 /5 /1 => /1 /2 */
|
||||
-#define MESON_VCLK_HDMI_DDR_148500 3
|
||||
-/* 4028 /4 /4 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_25175 4
|
||||
-/* 2560 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_32000 5
|
||||
-/* 2700 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_33750 6
|
||||
-/* 2712 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_33900 7
|
||||
-/* 2880 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_36000 8
|
||||
-/* 3200 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_40000 9
|
||||
-/* 5200 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_65000 10
|
||||
-/* 2970 /2 /2 /2 /5 /1 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_74250 11
|
||||
-/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_108000 12
|
||||
-/* 2970 /1 /2 /2 /5 /1 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_148500 13
|
||||
-/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_162000 14
|
||||
-/* 2970 /1 /1 /1 /5 /2 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_297000 15
|
||||
-/* 5940 /1 /1 /2 /5 /1 => /1 /1 */
|
||||
-#define MESON_VCLK_HDMI_594000 16
|
||||
+enum {
|
||||
+ /* PLL O1 O2 O3 VP DV EN TX */
|
||||
+ /* 4320 /4 /4 /1 /5 /1 => /2 /2 */
|
||||
+ MESON_VCLK_HDMI_ENCI_54000 = 1,
|
||||
+ /* 4320 /4 /4 /1 /5 /1 => /1 /2 */
|
||||
+ MESON_VCLK_HDMI_DDR_54000,
|
||||
+ /* 2970 /4 /1 /1 /5 /1 => /1 /2 */
|
||||
+ MESON_VCLK_HDMI_DDR_148500,
|
||||
+ /* 4028 /4 /4 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_25175,
|
||||
+ /* 4760 /4 /4 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_29750,
|
||||
+ /* 2560 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_32000,
|
||||
+ /* 2700 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_33750,
|
||||
+ /* 2712 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_33900,
|
||||
+ /* 2880 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_36000,
|
||||
+ /* 3200 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_40000,
|
||||
+ /* 5200 /4 /2 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_65000,
|
||||
+ /* 2970 /2 /2 /2 /5 /1 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_74250,
|
||||
+ /* 4260 /4 /1 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_106500,
|
||||
+ /* 4320 /4 /1 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_108000,
|
||||
+ /* 2970 /1 /2 /2 /5 /1 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_148500,
|
||||
+ /* 3240 /2 /1 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_162000,
|
||||
+ /* 3865 /2 /1 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_193250,
|
||||
+ /* 2970 /1 /1 /1 /5 /2 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_297000,
|
||||
+ /* 5940 /1 /1 /2 /5 /1 => /1 /1 */
|
||||
+ MESON_VCLK_HDMI_594000,
|
||||
+ /* custom calculated mode */
|
||||
+ MESON_VCLK_HDMI_CUSTOM,
|
||||
+};
|
||||
|
||||
struct meson_vclk_params {
|
||||
unsigned int pll_base_freq;
|
||||
@@ -427,6 +437,14 @@
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 2,
|
||||
},
|
||||
+ [MESON_VCLK_HDMI_29750] = {
|
||||
+ .pll_base_freq = 4760000,
|
||||
+ .pll_od1 = 4,
|
||||
+ .pll_od2 = 4,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
[MESON_VCLK_HDMI_32000] = {
|
||||
.pll_base_freq = 5120000,
|
||||
.pll_od1 = 4,
|
||||
@@ -475,6 +493,14 @@
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 2,
|
||||
},
|
||||
+ [MESON_VCLK_HDMI_106500] = {
|
||||
+ .pll_base_freq = 4260000,
|
||||
+ .pll_od1 = 4,
|
||||
+ .pll_od2 = 1,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
[MESON_VCLK_HDMI_108000] = {
|
||||
.pll_base_freq = 4320000,
|
||||
.pll_od1 = 4,
|
||||
@@ -491,6 +517,14 @@
|
||||
.vid_pll_div = VID_PLL_DIV_5,
|
||||
.vclk_div = 2,
|
||||
},
|
||||
+ [MESON_VCLK_HDMI_193250] = {
|
||||
+ .pll_base_freq = 3865000,
|
||||
+ .pll_od1 = 2,
|
||||
+ .pll_od2 = 1,
|
||||
+ .pll_od3 = 1,
|
||||
+ .vid_pll_div = VID_PLL_DIV_5,
|
||||
+ .vclk_div = 2,
|
||||
+ },
|
||||
};
|
||||
|
||||
static inline unsigned int pll_od_to_reg(unsigned int od)
|
||||
@@ -519,6 +553,18 @@
|
||||
unsigned int val;
|
||||
|
||||
if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
|
||||
+ unsigned int step = 48000;
|
||||
+ unsigned int range = 0x1000;
|
||||
+ unsigned int round = step / range / 2;
|
||||
+ unsigned int frac = base % step;
|
||||
+ unsigned int m = (base - frac) / step;
|
||||
+
|
||||
+ frac = (frac + round) * range / step;
|
||||
+ if (frac >= range)
|
||||
+ frac = range-1;
|
||||
+
|
||||
+ dev_info(priv->dev, "%s: base=%d, m=0x%.2x, frac=0x%.3x\n", __func__, base, m, frac);
|
||||
+
|
||||
switch (base) {
|
||||
case 2700000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000238);
|
||||
@@ -755,10 +801,49 @@
|
||||
/* Poll for lock bit */
|
||||
regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+
|
||||
+ /* div_frac */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
+ 0xFFFF, 0x4555);
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
|
||||
+
|
||||
+ /* unreset */
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ BIT(28), 0);
|
||||
+
|
||||
+ /* Poll for lock bit */
|
||||
+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
|
||||
+ val, (val & HDMI_PLL_LOCK), 10, 0);
|
||||
+
|
||||
+ /* div_frac */
|
||||
+ if (frac)
|
||||
+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
|
||||
+ 0xFFFF, 0x4000 | frac);
|
||||
break;
|
||||
+
|
||||
};
|
||||
} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
|
||||
meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
|
||||
+ unsigned int step = 24000;
|
||||
+ unsigned int range = 0x400;
|
||||
+ unsigned int round = step / range / 2;
|
||||
+ unsigned int frac = base % step;
|
||||
+ unsigned int m = (base - frac) / step;
|
||||
+
|
||||
+ frac = (frac + round) * range / step;
|
||||
+ if (frac >= range)
|
||||
+ frac = range-1;
|
||||
+
|
||||
+ pr_info("%s: base=%d, m=0x%.2x, frac=0x%.3x", __func__, base, m, frac);
|
||||
+
|
||||
switch (base) {
|
||||
case 2700000:
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000270);
|
||||
@@ -868,6 +953,14 @@
|
||||
regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
break;
|
||||
|
||||
+ default:
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
|
||||
+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
|
||||
+ break;
|
||||
};
|
||||
|
||||
/* Reset PLL */
|
||||
@@ -906,6 +999,151 @@
|
||||
3 << 19, pll_od_to_reg(od3) << 19);
|
||||
}
|
||||
|
||||
+unsigned int meson_vclk_freq_from_params(struct meson_vclk_params* vclk_params)
|
||||
+{
|
||||
+ unsigned int vclk_freq = vclk_params->pll_base_freq /
|
||||
+ vclk_params->pll_od1 / vclk_params->pll_od2 /
|
||||
+ vclk_params->pll_od3 / vclk_params->vclk_div;
|
||||
+
|
||||
+ switch (vclk_params->vid_pll_div) {
|
||||
+ case VID_PLL_DIV_2:
|
||||
+ vclk_freq /= 2;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_2p5:
|
||||
+ vclk_freq *= 4;
|
||||
+ vclk_freq /= 10;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_3:
|
||||
+ vclk_freq /= 3;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_3p5:
|
||||
+ vclk_freq *= 2;
|
||||
+ vclk_freq /= 7;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_3p75:
|
||||
+ vclk_freq *= 4;
|
||||
+ vclk_freq /= 15;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_4:
|
||||
+ vclk_freq /= 4;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_5:
|
||||
+ vclk_freq /= 5;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_6:
|
||||
+ vclk_freq /= 6;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_6p25:
|
||||
+ vclk_freq *= 8;
|
||||
+ vclk_freq /= 50;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_7:
|
||||
+ vclk_freq /= 7;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_7p5:
|
||||
+ vclk_freq *= 4;
|
||||
+ vclk_freq /= 30;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_12:
|
||||
+ vclk_freq /= 12;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_14:
|
||||
+ vclk_freq /= 14;
|
||||
+ break;
|
||||
+ case VID_PLL_DIV_15:
|
||||
+ vclk_freq /= 15;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return vclk_freq;
|
||||
+}
|
||||
+
|
||||
+static bool meson_get_vclk_params(unsigned int freq,
|
||||
+ struct meson_vclk_params* vclk_params)
|
||||
+{
|
||||
+ unsigned int vclk_freq = freq;
|
||||
+ unsigned int base_freq, od1_od2, od3_vpll_vclk;
|
||||
+ int p, jit;
|
||||
+ bool found = false;
|
||||
+
|
||||
+ if ((vclk_freq < 13500) || (vclk_freq > 594000))
|
||||
+ return false;
|
||||
+
|
||||
+ if (vclk_freq % 25 > 12)
|
||||
+ vclk_freq += 25;
|
||||
+ vclk_freq -= vclk_freq % 25;
|
||||
+
|
||||
+ for (p = 1; p < sizeof(params) / sizeof(struct meson_vclk_params); p++) {
|
||||
+ if (params[p].vid_pll_div != VID_PLL_DIV_5)
|
||||
+ continue;
|
||||
+
|
||||
+ od1_od2 = params[p].pll_od1 * params[p].pll_od2;
|
||||
+ od3_vpll_vclk = params[p].pll_od3 * 5 * params[p].vclk_div;
|
||||
+
|
||||
+ if ((od3_vpll_vclk != 10) && (vclk_freq > 54000 + 175))
|
||||
+ continue;
|
||||
+
|
||||
+ base_freq = vclk_freq * od1_od2 * od3_vpll_vclk;
|
||||
+
|
||||
+ if ((base_freq < 2700000) || (base_freq > 5940000))
|
||||
+ continue;
|
||||
+
|
||||
+ vclk_params->pll_base_freq = base_freq;
|
||||
+ vclk_params->pll_od1 = params[p].pll_od1;
|
||||
+ vclk_params->pll_od2 = params[p].pll_od2;
|
||||
+ vclk_params->pll_od3 = params[p].pll_od3;
|
||||
+ vclk_params->vid_pll_div = params[p].vid_pll_div;
|
||||
+ vclk_params->vclk_div = params[p].vclk_div;
|
||||
+
|
||||
+ found = true;
|
||||
+
|
||||
+ if (params[p].pll_base_freq > vclk_params->pll_base_freq)
|
||||
+ jit = params[p].pll_base_freq - vclk_params->pll_base_freq;
|
||||
+ else
|
||||
+ jit = vclk_params->pll_base_freq - params[p].pll_base_freq;
|
||||
+
|
||||
+ if (jit < 175 * od1_od2 * od3_vpll_vclk) {
|
||||
+ vclk_params->pll_base_freq = params[p].pll_base_freq;
|
||||
+ vclk_freq = vclk_params->pll_base_freq / od1_od2 / od3_vpll_vclk;
|
||||
+ }
|
||||
+
|
||||
+ if (jit < 40000)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return found;
|
||||
+}
|
||||
+
|
||||
+static void meson_print_vclk_params(struct meson_drm *priv, unsigned int freq,
|
||||
+ struct meson_vclk_params* vclk_params)
|
||||
+{
|
||||
+ unsigned int vclk_freq = meson_vclk_freq_from_params(vclk_params);
|
||||
+
|
||||
+ if (vclk_params->vid_pll_div != VID_PLL_DIV_5)
|
||||
+ return;
|
||||
+
|
||||
+ if (vclk_freq != freq)
|
||||
+ dev_info(priv->dev, "adjusted %d -> %d", freq, vclk_freq);
|
||||
+
|
||||
+ dev_info(priv->dev, "params %d / %d / %d / %d / %d / %d = %d\n",
|
||||
+ vclk_params->pll_base_freq,
|
||||
+ vclk_params->pll_od1,
|
||||
+ vclk_params->pll_od2,
|
||||
+ vclk_params->pll_od3,
|
||||
+ 5, vclk_params->vclk_div,
|
||||
+ vclk_freq);
|
||||
+}
|
||||
+
|
||||
+bool meson_vclk_supported(unsigned int vclk_freq)
|
||||
+{
|
||||
+ struct meson_vclk_params custom_params;
|
||||
+
|
||||
+ return (meson_get_vclk_params(vclk_freq, &custom_params));
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(meson_vclk_supported);
|
||||
+
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
unsigned int vclk_freq, unsigned int venc_freq,
|
||||
unsigned int dac_freq, bool hdmi_use_enci)
|
||||
@@ -913,6 +1151,8 @@
|
||||
unsigned int freq;
|
||||
unsigned int hdmi_tx_div;
|
||||
unsigned int venc_div;
|
||||
+ struct meson_vclk_params custom_params;
|
||||
+ struct meson_vclk_params* vclk_params;
|
||||
|
||||
if (target == MESON_VCLK_TARGET_CVBS) {
|
||||
meson_venci_cvbs_clock_config(priv);
|
||||
@@ -945,6 +1185,9 @@
|
||||
case 25175:
|
||||
freq = MESON_VCLK_HDMI_25175;
|
||||
break;
|
||||
+ case 29750:
|
||||
+ freq = MESON_VCLK_HDMI_29750;
|
||||
+ break;
|
||||
case 32000:
|
||||
freq = MESON_VCLK_HDMI_32000;
|
||||
break;
|
||||
@@ -966,6 +1209,9 @@
|
||||
case 74250:
|
||||
freq = MESON_VCLK_HDMI_74250;
|
||||
break;
|
||||
+ case 106500:
|
||||
+ freq = MESON_VCLK_HDMI_106500;
|
||||
+ break;
|
||||
case 108000:
|
||||
freq = MESON_VCLK_HDMI_108000;
|
||||
break;
|
||||
@@ -978,6 +1224,9 @@
|
||||
case 162000:
|
||||
freq = MESON_VCLK_HDMI_162000;
|
||||
break;
|
||||
+ case 193250:
|
||||
+ freq = MESON_VCLK_HDMI_193250;
|
||||
+ break;
|
||||
case 297000:
|
||||
freq = MESON_VCLK_HDMI_297000;
|
||||
break;
|
||||
@@ -985,9 +1234,8 @@
|
||||
freq = MESON_VCLK_HDMI_594000;
|
||||
break;
|
||||
default:
|
||||
- pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
|
||||
- vclk_freq);
|
||||
- return;
|
||||
+ freq = MESON_VCLK_HDMI_CUSTOM;
|
||||
+ break;
|
||||
}
|
||||
|
||||
/* Set HDMI-TX sys clock */
|
||||
@@ -998,20 +1246,35 @@
|
||||
regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
|
||||
CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
|
||||
|
||||
+ vclk_params = NULL;
|
||||
+
|
||||
+ if (freq != MESON_VCLK_HDMI_CUSTOM)
|
||||
+ vclk_params = ¶ms[freq];
|
||||
+ else if (meson_get_vclk_params(vclk_freq, &custom_params))
|
||||
+ vclk_params = &custom_params;
|
||||
+
|
||||
+ if (!vclk_params) {
|
||||
+ pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
|
||||
+ vclk_freq);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ meson_print_vclk_params(priv, vclk_freq, vclk_params);
|
||||
+
|
||||
/* Set HDMI PLL rate */
|
||||
- meson_hdmi_pll_set(priv, params[freq].pll_base_freq,
|
||||
- params[freq].pll_od1,
|
||||
- params[freq].pll_od2,
|
||||
- params[freq].pll_od3);
|
||||
+ meson_hdmi_pll_set(priv, vclk_params->pll_base_freq,
|
||||
+ vclk_params->pll_od1,
|
||||
+ vclk_params->pll_od2,
|
||||
+ vclk_params->pll_od3);
|
||||
|
||||
/* Setup vid_pll divider */
|
||||
- meson_vid_pll_set(priv, params[freq].vid_pll_div);
|
||||
+ meson_vid_pll_set(priv, vclk_params->vid_pll_div);
|
||||
|
||||
/* Set VCLK div */
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
|
||||
VCLK_SEL_MASK, 0);
|
||||
regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
|
||||
- VCLK_DIV_MASK, params[freq].vclk_div - 1);
|
||||
+ VCLK_DIV_MASK, vclk_params->vclk_div - 1);
|
||||
|
||||
/* Set HDMI-TX source */
|
||||
switch (hdmi_tx_div) {
|
||||
diff -ur a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.h 2018-05-26 22:29:37.112948771 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.h 2018-05-31 05:15:53.342134304 +0200
|
||||
@@ -29,6 +29,8 @@
|
||||
/* 27MHz is the CVBS Pixel Clock */
|
||||
#define MESON_VCLK_CVBS 27000
|
||||
|
||||
+bool meson_vclk_supported(unsigned int vclk_freq);
|
||||
+
|
||||
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
|
||||
unsigned int vclk_freq, unsigned int venc_freq,
|
||||
unsigned int dac_freq, bool hdmi_use_enci);
|
||||
diff -ur a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.c 2018-06-02 20:23:23.744646670 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.c 2018-06-02 17:25:33.807332121 +0200
|
||||
@@ -707,6 +707,12 @@
|
||||
752, 800, 0, 480, 490, 492, 525, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
},
|
||||
+ /* 800x480@60Hz */
|
||||
+ {
|
||||
+ { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 29750, 800, 824,
|
||||
+ 896, 992, 0, 480, 483, 490, 500, 0,
|
||||
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
+ },
|
||||
/* 800x600@60Hz */
|
||||
{
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
|
||||
@@ -737,6 +743,12 @@
|
||||
1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
},
|
||||
+ /* 1440x900@60Hz */
|
||||
+ {
|
||||
+ { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440,
|
||||
+ 1520, 1672, 1904, 0, 900, 903, 909, 934, 0,
|
||||
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
+ },
|
||||
/* 1600x1200@60Hz */
|
||||
{
|
||||
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
|
||||
@@ -749,6 +761,12 @@
|
||||
2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
|
||||
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
|
||||
},
|
||||
+ /* 1920x1200@60Hz */
|
||||
+ {
|
||||
+ { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920,
|
||||
+ 2056, 2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
|
||||
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
+ },
|
||||
{ }, /* sentinel */
|
||||
};
|
||||
|
@ -0,0 +1,115 @@
|
||||
diff -u a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
|
||||
--- a/drivers/gpu/drm/meson/meson_vclk.c 2018-06-10 06:10:59.071504595 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_vclk.c 2018-06-10 05:33:51.347202114 +0200
|
||||
@@ -842,7 +842,7 @@
|
||||
if (frac >= range)
|
||||
frac = range-1;
|
||||
|
||||
- pr_info("%s: base=%d, m=0x%.2x, frac=0x%.3x", __func__, base, m, frac);
|
||||
+ dev_info(priv->dev, "%s: base=%d, m=0x%.2x, frac=0x%.3x\n", __func__, base, m, frac);
|
||||
|
||||
switch (base) {
|
||||
case 2700000:
|
||||
@@ -1065,25 +1065,36 @@
|
||||
{
|
||||
unsigned int vclk_freq = freq;
|
||||
unsigned int base_freq, od1_od2, od3_vpll_vclk;
|
||||
- int p, jit;
|
||||
+ int od1, od2, od3, p, jit;
|
||||
bool found = false;
|
||||
|
||||
- if ((vclk_freq < 13500) || (vclk_freq > 594000))
|
||||
+ if ((vclk_freq < 12000) || (vclk_freq > 594000))
|
||||
return false;
|
||||
|
||||
if (vclk_freq % 25 > 12)
|
||||
vclk_freq += 25;
|
||||
vclk_freq -= vclk_freq % 25;
|
||||
|
||||
- for (p = 1; p < sizeof(params) / sizeof(struct meson_vclk_params); p++) {
|
||||
- if (params[p].vid_pll_div != VID_PLL_DIV_5)
|
||||
+ for (p = 0; p < 6; p++) {
|
||||
+ od1 = (1 << p);
|
||||
+ od2 = 1;
|
||||
+ od3 = 1;
|
||||
+
|
||||
+ if ((vclk_freq > 18550) && (od1 > 16))
|
||||
continue;
|
||||
|
||||
- od1_od2 = params[p].pll_od1 * params[p].pll_od2;
|
||||
- od3_vpll_vclk = params[p].pll_od3 * 5 * params[p].vclk_div;
|
||||
+ if (od1 > 16) {
|
||||
+ od3 = od1 / 16;
|
||||
+ od1 = 16;
|
||||
+ }
|
||||
|
||||
- if ((od3_vpll_vclk != 10) && (vclk_freq > 54000 + 175))
|
||||
- continue;
|
||||
+ if (od1 > 4) {
|
||||
+ od2 = od1 / 4;
|
||||
+ od1 = 4;
|
||||
+ }
|
||||
+
|
||||
+ od1_od2 = od1 * od2;
|
||||
+ od3_vpll_vclk = od3 * 5 * 2;
|
||||
|
||||
base_freq = vclk_freq * od1_od2 * od3_vpll_vclk;
|
||||
|
||||
@@ -1091,21 +1102,32 @@
|
||||
continue;
|
||||
|
||||
vclk_params->pll_base_freq = base_freq;
|
||||
- vclk_params->pll_od1 = params[p].pll_od1;
|
||||
- vclk_params->pll_od2 = params[p].pll_od2;
|
||||
- vclk_params->pll_od3 = params[p].pll_od3;
|
||||
- vclk_params->vid_pll_div = params[p].vid_pll_div;
|
||||
- vclk_params->vclk_div = params[p].vclk_div;
|
||||
+ vclk_params->pll_od1 = od1;
|
||||
+ vclk_params->pll_od2 = od2;
|
||||
+ vclk_params->pll_od3 = od3;
|
||||
+ vclk_params->vid_pll_div = VID_PLL_DIV_5;
|
||||
+ vclk_params->vclk_div = 2;
|
||||
|
||||
found = true;
|
||||
|
||||
- if (params[p].pll_base_freq > vclk_params->pll_base_freq)
|
||||
- jit = params[p].pll_base_freq - vclk_params->pll_base_freq;
|
||||
+ jit = od1_od2 * od3_vpll_vclk * 125;
|
||||
+ if (p < 3)
|
||||
+ jit <<= (3-p);
|
||||
+
|
||||
+ if ((base_freq % 24000) < (base_freq % jit))
|
||||
+ jit = 24000;
|
||||
+
|
||||
+ if ((base_freq % jit) > (jit / 2))
|
||||
+ base_freq = base_freq+jit;
|
||||
+ base_freq -= base_freq % jit;
|
||||
+
|
||||
+ if (base_freq > vclk_params->pll_base_freq)
|
||||
+ jit = base_freq - vclk_params->pll_base_freq;
|
||||
else
|
||||
- jit = vclk_params->pll_base_freq - params[p].pll_base_freq;
|
||||
+ jit = vclk_params->pll_base_freq - base_freq;
|
||||
|
||||
if (jit < 175 * od1_od2 * od3_vpll_vclk) {
|
||||
- vclk_params->pll_base_freq = params[p].pll_base_freq;
|
||||
+ vclk_params->pll_base_freq = base_freq;
|
||||
vclk_freq = vclk_params->pll_base_freq / od1_od2 / od3_vpll_vclk;
|
||||
}
|
||||
|
||||
diff -u a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
|
||||
--- a/drivers/gpu/drm/meson/meson_venc.c 2018-06-10 06:10:59.071504595 +0200
|
||||
+++ b/drivers/gpu/drm/meson/meson_venc.c 2018-06-10 05:26:59.995203463 +0200
|
||||
@@ -816,10 +816,10 @@
|
||||
DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))
|
||||
return MODE_BAD;
|
||||
|
||||
- if (mode->hdisplay < 640 || mode->hdisplay > 1920)
|
||||
+ if (mode->hdisplay < 416 || mode->hdisplay > 1920)
|
||||
return MODE_BAD_HVALUE;
|
||||
|
||||
- if (mode->vdisplay < 480 || mode->vdisplay > 1200)
|
||||
+ if (mode->vdisplay < 360 || mode->vdisplay > 1200)
|
||||
return MODE_BAD_VVALUE;
|
||||
|
||||
return MODE_OK;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,151 @@
|
||||
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
|
||||
index cab14f25..cafc60ea 100644
|
||||
--- a/drivers/gpu/drm/drm_fb_helper.c
|
||||
+++ b/drivers/gpu/drm/drm_fb_helper.c
|
||||
@@ -1544,6 +1544,14 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
|
||||
ret = 0;
|
||||
goto unlock;
|
||||
+#if defined(CONFIG_UMP)
|
||||
+ case GET_UMP_SECURE_ID_BUF1:
|
||||
+ ret = drm_get_ump_secure_id(info, fb_helper, arg, 0);
|
||||
+ goto unlock;
|
||||
+ case GET_UMP_SECURE_ID_BUF2:
|
||||
+ ret = drm_get_ump_secure_id(info, fb_helper, arg, 1);
|
||||
+ goto unlock;
|
||||
+#endif
|
||||
default:
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
|
||||
index 69c13517..55673ac6 100644
|
||||
--- a/drivers/gpu/drm/Makefile
|
||||
+++ b/drivers/gpu/drm/Makefile
|
||||
@@ -44,6 +44,7 @@ drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
|
||||
|
||||
obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
|
||||
obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
|
||||
+obj-$(CONFIG_UMP) += drm_fb_ump.o
|
||||
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
|
||||
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
|
||||
index b069433e..95657b76 100644
|
||||
--- a/include/drm/drm_fb_helper.h
|
||||
+++ b/include/drm/drm_fb_helper.h
|
||||
@@ -36,6 +36,10 @@ struct drm_fb_helper;
|
||||
#include <drm/drm_device.h>
|
||||
#include <linux/kgdb.h>
|
||||
|
||||
+#if defined(CONFIG_UMP)
|
||||
+#include <ump/ump_kernel_interface.h>
|
||||
+#endif
|
||||
+
|
||||
enum mode_set_atomic {
|
||||
LEAVE_ATOMIC_MODE_SET,
|
||||
ENTER_ATOMIC_MODE_SET,
|
||||
@@ -131,6 +135,8 @@ struct drm_fb_helper_connector {
|
||||
struct drm_connector *connector;
|
||||
};
|
||||
|
||||
+#define DRM_FB_UMP_COUNT 1 /* only enable one FB UMP layer */
|
||||
+
|
||||
/**
|
||||
* struct drm_fb_helper - main structure to emulate fbdev on top of KMS
|
||||
* @fb: Scanout framebuffer object
|
||||
@@ -232,6 +238,9 @@ struct drm_fb_helper {
|
||||
* See also: @deferred_setup
|
||||
*/
|
||||
int preferred_bpp;
|
||||
+#if defined(CONFIG_UMP)
|
||||
+ ump_dd_handle ump_wrapped_buffer[DRM_FB_UMP_COUNT][2];
|
||||
+#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -577,4 +586,11 @@ drm_fb_helper_remove_conflicting_framebuffers(struct apertures_struct *a,
|
||||
#endif
|
||||
}
|
||||
|
||||
+#if defined(CONFIG_UMP)
|
||||
+extern int (*drm_get_ump_secure_id) (struct fb_info *info,
|
||||
+ struct drm_fb_helper *g_fbi, unsigned long arg, int buf);
|
||||
+#define GET_UMP_SECURE_ID_BUF1 _IOWR('m', 311, unsigned int)
|
||||
+#define GET_UMP_SECURE_ID_BUF2 _IOWR('m', 312, unsigned int)
|
||||
+#endif
|
||||
+
|
||||
#endif
|
||||
--- /dev/null 2018-07-12 16:39:19.544000000 +0200
|
||||
+++ b/drivers/gpu/drm/drm_fb_ump.c 2018-07-22 22:20:45.166145058 +0200
|
||||
@@ -0,0 +1,71 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2016 Hardkernel Co. Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of
|
||||
+ * the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
+ * MA 02111-1307 USA
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+
|
||||
+#include <ump/ump_kernel_interface_ref_drv.h>
|
||||
+#include <ump/ump_kernel_interface.h>
|
||||
+#include <asm/uaccess.h>
|
||||
+#include <drm/drmP.h>
|
||||
+#include <drm/drm_fb_helper.h>
|
||||
+
|
||||
+int (*drm_get_ump_secure_id) (struct fb_info *info,
|
||||
+ struct drm_fb_helper *g_fbi, unsigned long arg, int buf);
|
||||
+EXPORT_SYMBOL(drm_get_ump_secure_id);
|
||||
+
|
||||
+static int _drm_get_ump_secure_id(struct fb_info *info,
|
||||
+ struct drm_fb_helper *g_fbi, unsigned long arg, int buf)
|
||||
+{
|
||||
+ u32 __user *psecureid = (u32 __user *) arg;
|
||||
+ ump_secure_id secure_id;
|
||||
+
|
||||
+ if (!g_fbi->ump_wrapped_buffer[info->node][buf]) {
|
||||
+ ump_dd_physical_block ump_memory_description;
|
||||
+ printk("ump: create disp: %d\n", buf);
|
||||
+
|
||||
+ ump_memory_description.addr = info->fix.smem_start;
|
||||
+ ump_memory_description.size = info->fix.smem_len;
|
||||
+ g_fbi->ump_wrapped_buffer[info->node][buf] =
|
||||
+ ump_dd_handle_create_from_phys_blocks(
|
||||
+ &ump_memory_description, 1);
|
||||
+ }
|
||||
+ secure_id = ump_dd_secure_id_get(
|
||||
+ g_fbi->ump_wrapped_buffer[info->node][buf]);
|
||||
+
|
||||
+ return put_user((unsigned int)secure_id, psecureid);
|
||||
+}
|
||||
+
|
||||
+static int __init drm_ump_module_init(void)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ drm_get_ump_secure_id = _drm_get_ump_secure_id;
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void __exit drm_ump_module_exit(void)
|
||||
+{
|
||||
+ drm_get_ump_secure_id = NULL;
|
||||
+}
|
||||
+
|
||||
+module_init(drm_ump_module_init);
|
||||
+module_exit(drm_ump_module_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Mauro Ribeiro <mauro.ribeiro@hardkernel.com>");
|
||||
+MODULE_DESCRIPTION("UMP Glue for DRM Framebuffer");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,14 @@
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index d147c853a..dbde670ba 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -246,7 +246,8 @@
|
||||
};
|
||||
|
||||
&scpi_clocks {
|
||||
- status = "disabled";
|
||||
+ /* Works only with new blobs that have limited DVFS table */
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
/* SD */
|
@ -0,0 +1,63 @@
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-04-29 05:46:55.636313674 +0200
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-04-29 00:07:14.412005049 +0200
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "meson-gxbb.dtsi"
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
+#include <dt-bindings/thermal/thermal.h>
|
||||
|
||||
/ {
|
||||
compatible = "hardkernel,odroid-c2", "amlogic,meson-gxbb";
|
||||
@@ -117,6 +118,41 @@
|
||||
1800000 1>;
|
||||
};
|
||||
|
||||
+ thermal-zones {
|
||||
+ cpu-thermal {
|
||||
+ polling-delay-passive = <250>; /* milliseconds */
|
||||
+ polling-delay = <1000>; /* milliseconds */
|
||||
+
|
||||
+ thermal-sensors = <&scpi_sensors 0>;
|
||||
+
|
||||
+ trips {
|
||||
+ cpu_alert0: cpu-alert0 {
|
||||
+ temperature = <70000>;
|
||||
+ hysteresis = <2000>;
|
||||
+ type = "passive";
|
||||
+ };
|
||||
+ cpu_alert1: cpu-alert1 {
|
||||
+ temperature = <85000>;
|
||||
+ hysteresis = <2000>;
|
||||
+ type = "passive";
|
||||
+ };
|
||||
+ cpu_crit: cpu_crit {
|
||||
+ temperature = <95000>;
|
||||
+ hysteresis = <2000>;
|
||||
+ type = "critical";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ cooling-maps {
|
||||
+ map0 {
|
||||
+ trip = <&cpu_alert1>;
|
||||
+ cooling-device =
|
||||
+ <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
vcc1v8: regulator-vcc1v8 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VCC1V8";
|
||||
@@ -192,6 +228,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
+&cpu0 {
|
||||
+ #cooling-cells = <2>;
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-0 = <ð_rgmii_pins>;
|
@ -0,0 +1,19 @@
|
||||
|
||||
--- b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 2018-04-12 01:40:29.029325568 +0200
|
||||
+++ a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c 2018-04-14 01:12:07.301469106 +0200
|
||||
@@ -364,15 +364,9 @@
|
||||
bool stmmac_eee_init(struct stmmac_priv *priv)
|
||||
{
|
||||
struct net_device *ndev = priv->dev;
|
||||
- int interface = priv->plat->interface;
|
||||
unsigned long flags;
|
||||
bool ret = false;
|
||||
|
||||
- if ((interface != PHY_INTERFACE_MODE_MII) &&
|
||||
- (interface != PHY_INTERFACE_MODE_GMII) &&
|
||||
- !phy_interface_mode_is_rgmii(interface))
|
||||
- goto out;
|
||||
-
|
||||
/* Using PCS we cannot dial with the phy registers at this stage
|
||||
* so we do not support extra feature like EEE.
|
||||
*/
|
@ -1,7 +1,7 @@
|
||||
From 841ec7b8484dee021a15fdc187cdadc1c89220f2 Mon Sep 17 00:00:00 2001
|
||||
From 9724ee442cf7bf4da885433b28029ac559f1f26a Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Thu, 12 Jan 2017 01:38:26 +0100
|
||||
Subject: [PATCH 02/39] ARM64: dts: meson-gxbb: allow child devices on the USB
|
||||
Subject: [PATCH] ARM64: dts: meson-gxbb: allow child devices on the USB
|
||||
controller
|
||||
|
||||
Add the size and adress cells to the USB controllers to allow specifying
|
||||
@ -15,7 +15,7 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index af834cd..7d38d55 100644
|
||||
index af834cdbba791..7d38d55869c94 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -73,6 +73,8 @@
|
||||
@ -36,6 +36,3 @@ index af834cd..7d38d55 100644
|
||||
reg = <0x0 0xc9100000 0x0 0x40000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
|
||||
--
|
||||
2.7.4
|
||||
|
@ -1,8 +1,7 @@
|
||||
From 564bc89139a6bf0833cef64993dfe3fe2784c6a8 Mon Sep 17 00:00:00 2001
|
||||
From 53d19221222d8fe49aae75721a9547c7d104e9ed Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Thu, 12 Jan 2017 01:39:20 +0100
|
||||
Subject: [PATCH 03/39] ARM64: dts: meson-gxbb-odroidc2: take USB hub out of
|
||||
reset
|
||||
Subject: [PATCH] ARM64: dts: meson-gxbb-odroidc2: take USB hub out of reset
|
||||
|
||||
This takes the USB hub out of reset, otherwise the hub is not working.
|
||||
|
||||
@ -14,10 +13,10 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 08b7bb7..c3a7b7f 100644
|
||||
index 1ffa1c238a725..b035c728a4821 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -310,4 +310,11 @@
|
||||
@@ -309,4 +309,11 @@
|
||||
|
||||
&usb1 {
|
||||
status = "okay";
|
||||
@ -29,6 +28,3 @@ index 08b7bb7..c3a7b7f 100644
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
--
|
||||
2.7.4
|
||||
|
@ -0,0 +1,257 @@
|
||||
From 1b68976e2e05b3e10e4f3070ef5b9e08640ad7a0 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 26 Nov 2016 15:56:32 +0100
|
||||
Subject: [PATCH] phy: meson: add USB3 PHY support for Meson GXL
|
||||
|
||||
This adds USB3 PHY driver found on Meson GXL and GXM SoCs.
|
||||
|
||||
Unfortunately there are no datasheets available for any of these PHYs.
|
||||
Both drivers were written by reading the reference drivers provided by
|
||||
Amlogic and analyzing the registers on the kernel that was shipped with
|
||||
my board.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/phy/amlogic/Kconfig | 13 ++
|
||||
drivers/phy/amlogic/Makefile | 1 +
|
||||
drivers/phy/amlogic/phy-meson-gxl-usb3.c | 198 +++++++++++++++++++++++++++++++
|
||||
3 files changed, 212 insertions(+)
|
||||
create mode 100644 drivers/phy/amlogic/phy-meson-gxl-usb3.c
|
||||
|
||||
diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
|
||||
index cb8f4501652b1..5d11a3e698d4a 100644
|
||||
--- a/drivers/phy/amlogic/Kconfig
|
||||
+++ b/drivers/phy/amlogic/Kconfig
|
||||
@@ -13,6 +13,19 @@ config PHY_MESON8B_USB2
|
||||
Meson8b and GXBB SoCs.
|
||||
If unsure, say N.
|
||||
|
||||
+config PHY_MESON_GXL_USB3
|
||||
+ tristate "Meson GXL and GXM USB3 PHY drivers"
|
||||
+ default ARCH_MESON
|
||||
+ depends on OF && (ARCH_MESON || COMPILE_TEST)
|
||||
+ depends on USB_SUPPORT
|
||||
+ select USB_COMMON
|
||||
+ select GENERIC_PHY
|
||||
+ select REGMAP_MMIO
|
||||
+ help
|
||||
+ Enable this to support the Meson USB3 PHY found in Meson
|
||||
+ GXL and GXM SoCs.
|
||||
+ If unsure, say N.
|
||||
+
|
||||
config PHY_MESON_GXL_USB2
|
||||
tristate "Meson GXL and GXM USB2 PHY drivers"
|
||||
default ARCH_MESON
|
||||
diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile
|
||||
index cfdc98715c30a..4fd8848c194d6 100644
|
||||
--- a/drivers/phy/amlogic/Makefile
|
||||
+++ b/drivers/phy/amlogic/Makefile
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
|
||||
obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o
|
||||
+obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o
|
||||
diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb3.c b/drivers/phy/amlogic/phy-meson-gxl-usb3.c
|
||||
new file mode 100644
|
||||
index 0000000000000..9af5222fe754f
|
||||
--- /dev/null
|
||||
+++ b/drivers/phy/amlogic/phy-meson-gxl-usb3.c
|
||||
@@ -0,0 +1,198 @@
|
||||
+/*
|
||||
+ * Meson GXL USB3 PHY driver
|
||||
+ *
|
||||
+ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of_device.h>
|
||||
+#include <linux/reset.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/usb/of.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+#define USB_R0 0x00
|
||||
+ #define USB_R0_P30_FSEL_SHIFT 0
|
||||
+ #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
|
||||
+ #define USB_R0_P30_PHY_RESET BIT(6)
|
||||
+ #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
|
||||
+ #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
|
||||
+ #define USB_R0_P30_ACJT_LEVEL_SHIFT 9
|
||||
+ #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
|
||||
+ #define USB_R0_P30_TX_BOOST_LEVEL_SHIFT 14
|
||||
+ #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
|
||||
+ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
|
||||
+ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
|
||||
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
|
||||
+ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
|
||||
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
|
||||
+ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
|
||||
+ #define USB_R0_U2D_ACT BIT(31)
|
||||
+
|
||||
+#define USB_R1 0x04
|
||||
+ #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
|
||||
+ #define USB_R1_U3H_PME_ENABLE BIT(1)
|
||||
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
|
||||
+ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
|
||||
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
|
||||
+ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
|
||||
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
|
||||
+ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
|
||||
+ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
|
||||
+ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
|
||||
+ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
|
||||
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
|
||||
+ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
|
||||
+ #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
|
||||
+ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
|
||||
+
|
||||
+#define USB_R2 0x08
|
||||
+ #define USB_R2_P30_CR_DATA_IN_SHIFT 0
|
||||
+ #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
|
||||
+ #define USB_R2_P30_CR_READ BIT(16)
|
||||
+ #define USB_R2_P30_CR_WRITE BIT(17)
|
||||
+ #define USB_R2_P30_CR_CAP_ADDR BIT(18)
|
||||
+ #define USB_R2_P30_CR_CAP_DATA BIT(19)
|
||||
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
|
||||
+ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
|
||||
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
|
||||
+ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
|
||||
+
|
||||
+#define USB_R3 0x0c
|
||||
+ #define USB_R3_P30_SSC_ENABLE BIT(0)
|
||||
+ #define USB_R3_P30_SSC_RANGE_SHIFT 1
|
||||
+ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
|
||||
+ #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
|
||||
+ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
|
||||
+ #define USB_R3_P30_REF_SSP_EN BIT(13)
|
||||
+ #define USB_R3_P30_LOS_BIAS_SHIFT 16
|
||||
+ #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
|
||||
+ #define USB_R3_P30_LOS_LEVEL_SHIFT 19
|
||||
+ #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
|
||||
+ #define USB_R3_P30_MPLL_MULTIPLIER_SHIFT 24
|
||||
+ #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
|
||||
+
|
||||
+#define USB_R4 0x10
|
||||
+ #define USB_R4_P21_PORT_RESET_0 BIT(0)
|
||||
+ #define USB_R4_P21_SLEEP_M0 BIT(1)
|
||||
+ #define USB_R4_MEM_PD_SHIFT 2
|
||||
+ #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
|
||||
+ #define USB_R4_P21_ONLY BIT(4)
|
||||
+
|
||||
+#define USB_R5 0x14
|
||||
+ #define USB_R5_ID_DIG_SYNC BIT(0)
|
||||
+ #define USB_R5_ID_DIG_REG BIT(1)
|
||||
+ #define USB_R5_ID_DIG_CFG_SHIFT 2
|
||||
+ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
|
||||
+ #define USB_R5_ID_DIG_EN_0 BIT(4)
|
||||
+ #define USB_R5_ID_DIG_EN_1 BIT(5)
|
||||
+ #define USB_R5_ID_DIG_CURR BIT(6)
|
||||
+ #define USB_R5_ID_DIG_IRQ BIT(7)
|
||||
+ #define USB_R5_ID_DIG_TH_SHIFT 8
|
||||
+ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
|
||||
+ #define USB_R5_ID_DIG_CNT_SHIFT 16
|
||||
+ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
|
||||
+
|
||||
+/* read-only register */
|
||||
+#define USB_R6 0x18
|
||||
+ #define USB_R6_P30_CR_DATA_OUT_SHIFT 0
|
||||
+ #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
|
||||
+ #define USB_R6_P30_CR_ACK BIT(16)
|
||||
+
|
||||
+#define RESET_COMPLETE_TIME 500
|
||||
+
|
||||
+struct phy_meson_gxl_usb3_priv {
|
||||
+ struct regmap *regmap;
|
||||
+ struct phy *this_phy;
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
|
||||
+ .reg_bits = 32,
|
||||
+ .val_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+ .max_register = USB_R6,
|
||||
+};
|
||||
+
|
||||
+static int phy_meson_gxl_usb3_power_on(struct phy *phy)
|
||||
+{
|
||||
+ struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
|
||||
+
|
||||
+ regmap_update_bits(priv->regmap, USB_R1,
|
||||
+ USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
|
||||
+ 0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct phy_ops phy_meson_gxl_usb3_ops = {
|
||||
+ .power_on = phy_meson_gxl_usb3_power_on,
|
||||
+ .owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ struct phy_meson_gxl_usb3_priv *priv;
|
||||
+ struct resource *res;
|
||||
+ struct phy *phy;
|
||||
+ struct phy_provider *phy_provider;
|
||||
+ void __iomem *base;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ base = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(base))
|
||||
+ return PTR_ERR(base);
|
||||
+
|
||||
+ priv->regmap = devm_regmap_init_mmio(dev, base,
|
||||
+ &phy_meson_gxl_usb3_regmap_conf);
|
||||
+ if (IS_ERR(priv->regmap))
|
||||
+ return PTR_ERR(priv->regmap);
|
||||
+
|
||||
+ phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
|
||||
+ if (IS_ERR(phy)) {
|
||||
+ dev_err(dev, "failed to create PHY\n");
|
||||
+ return PTR_ERR(phy);
|
||||
+ }
|
||||
+
|
||||
+ phy_set_drvdata(phy, priv);
|
||||
+
|
||||
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
+
|
||||
+ return PTR_ERR_OR_ZERO(phy_provider);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-gxl-usb3-phy", },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
|
||||
+
|
||||
+static struct platform_driver phy_meson_gxl_usb3_driver = {
|
||||
+ .probe = phy_meson_gxl_usb3_probe,
|
||||
+ .driver = {
|
||||
+ .name = "phy-meson-gxl-usb3",
|
||||
+ .of_match_table = phy_meson_gxl_usb3_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(phy_meson_gxl_usb3_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
|
||||
+MODULE_DESCRIPTION("Meson GXL USB3 PHY driver");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,290 @@
|
||||
From 0e1b7fc3afdff8b63a2ed34ae6222cc02b043d62 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Tue, 10 Jan 2017 18:59:43 +0100
|
||||
Subject: [PATCH] usb: host: add a generic platform USB roothub driver
|
||||
|
||||
Many SoC platforms have separate devices for the USB PHY which are
|
||||
registered through the generic PHY framework. These PHYs have to be
|
||||
enabled to make the USB controller actually work. They also have to be
|
||||
disabled again on shutdown/suspend.
|
||||
|
||||
Currently (at least) the following HCI platform drivers are using custom
|
||||
code to obtain all PHYs via devicetree for the roothub/controller and
|
||||
disable/enable them when required:
|
||||
- ehci-platform.c has ehci_platform_power_{on,off}
|
||||
- xhci-mtk.c has xhci_mtk_phy_{init,exit,power_on,power_off}
|
||||
- ohci-platform.c has ohci_platform_power_{on,off}
|
||||
|
||||
These drivers are not using the generic devicetree USB device bindings
|
||||
yet which were only introduced recently (documentation is available in
|
||||
devicetree/bindings/usb/usb-device.txt).
|
||||
With this new driver the usb2-phy and usb3-phy can be specified directly
|
||||
in the child-node of the corresponding port of the roothub via
|
||||
devicetree. This can be extended by not just parsing PHYs (some of the
|
||||
other drivers listed above are for example also parsing a list of clocks
|
||||
as well) when required.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../devicetree/bindings/usb/usb-roothub.txt | 46 +++++++
|
||||
drivers/usb/host/Kconfig | 3 +
|
||||
drivers/usb/host/Makefile | 2 +
|
||||
drivers/usb/host/platform-roothub.c | 146 +++++++++++++++++++++
|
||||
drivers/usb/host/platform-roothub.h | 14 ++
|
||||
5 files changed, 211 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/usb/usb-roothub.txt
|
||||
create mode 100644 drivers/usb/host/platform-roothub.c
|
||||
create mode 100644 drivers/usb/host/platform-roothub.h
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/usb/usb-roothub.txt b/Documentation/devicetree/bindings/usb/usb-roothub.txt
|
||||
new file mode 100644
|
||||
index 0000000000000..23b24b68d74df
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-roothub.txt
|
||||
@@ -0,0 +1,46 @@
|
||||
+Generic USB root-hub Properties
|
||||
+
|
||||
+similar to the USB device bindings (documented in usb-device.txt from the
|
||||
+current directory) this provides support for configuring the root-hub.
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: should be at least one of "usb1d6b,3", "usb1d6b,2"
|
||||
+- reg: must be 0.
|
||||
+- address-cells: must be 1
|
||||
+- size-cells: must be 0
|
||||
+
|
||||
+Required sub-nodes:
|
||||
+a sub-node per actual USB port is required. each sub-node supports the
|
||||
+following properties:
|
||||
+ Required properties:
|
||||
+ - reg: the port number on the root-hub (mandatory)
|
||||
+ Optional properties:
|
||||
+ - phys: optional, from the *Generic PHY* bindings (mandatory needed
|
||||
+ when phy-names is given)
|
||||
+ - phy-names: optional, from the *Generic PHY* bindings; supported names
|
||||
+ are "usb2-phy" or "usb3-phy"
|
||||
+
|
||||
+Example:
|
||||
+ &usb1 {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ roothub@0 {
|
||||
+ compatible = "usb1d6b,3", "usb1d6b,2";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reg = <0>;
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ usb-phy = <&usb2_phy1>, <&usb3_phy1>;
|
||||
+ phy-names = "usb2-phy", "usb3-phy";
|
||||
+ };
|
||||
+
|
||||
+ port@2 {
|
||||
+ reg = <2>;
|
||||
+ usb-phy = <&usb2_phy2>, <&usb3_phy2>;
|
||||
+ phy-names = "usb2-phy", "usb3-phy";
|
||||
+ };
|
||||
+ };
|
||||
+ }
|
||||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
|
||||
index fa5692dec8320..b8b05c786b2a2 100644
|
||||
--- a/drivers/usb/host/Kconfig
|
||||
+++ b/drivers/usb/host/Kconfig
|
||||
@@ -805,6 +805,9 @@ config USB_HCD_SSB
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
+config USB_PLATFORM_ROOTHUB
|
||||
+ bool
|
||||
+
|
||||
config USB_HCD_TEST_MODE
|
||||
bool "HCD test mode support"
|
||||
---help---
|
||||
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
|
||||
index 4ab2689c8952b..873ebd9250d3b 100644
|
||||
--- a/drivers/usb/host/Makefile
|
||||
+++ b/drivers/usb/host/Makefile
|
||||
@@ -30,6 +30,8 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
obj-$(CONFIG_USB_PCI) += pci-quirks.o
|
||||
|
||||
+obj-$(CONFIG_USB_PLATFORM_ROOTHUB) += platform-roothub.o
|
||||
+
|
||||
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
|
||||
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
||||
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
|
||||
diff --git a/drivers/usb/host/platform-roothub.c b/drivers/usb/host/platform-roothub.c
|
||||
new file mode 100644
|
||||
index 0000000000000..84837e42b0063
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/host/platform-roothub.c
|
||||
@@ -0,0 +1,146 @@
|
||||
+/*
|
||||
+ * platform roothub driver - a virtual PHY device which passes all phy_*
|
||||
+ * function calls to multiple (actual) PHY devices. This is comes handy when
|
||||
+ * initializing all PHYs on a root-hub (to keep them all in the same state).
|
||||
+ *
|
||||
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/usb/of.h>
|
||||
+
|
||||
+#include "platform-roothub.h"
|
||||
+
|
||||
+#define ROOTHUB_PORTNUM 0
|
||||
+
|
||||
+struct platform_roothub {
|
||||
+ struct phy *phy;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+static struct platform_roothub *platform_roothub_alloc(struct device *dev)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+
|
||||
+ roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
|
||||
+ if (!roothub_entry)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ INIT_LIST_HEAD(&roothub_entry->list);
|
||||
+
|
||||
+ return roothub_entry;
|
||||
+}
|
||||
+
|
||||
+static int platform_roothub_add_phy(struct device *dev,
|
||||
+ struct device_node *port_np,
|
||||
+ const char *con_id, struct list_head *list)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+ struct phy *phy = devm_of_phy_get(dev, port_np, con_id);
|
||||
+
|
||||
+ if (IS_ERR_OR_NULL(phy)) {
|
||||
+ if (!phy || PTR_ERR(phy) == -ENODEV)
|
||||
+ return 0;
|
||||
+ else
|
||||
+ return PTR_ERR(phy);
|
||||
+ }
|
||||
+
|
||||
+ roothub_entry = platform_roothub_alloc(dev);
|
||||
+ if (IS_ERR(roothub_entry))
|
||||
+ return PTR_ERR(roothub_entry);
|
||||
+
|
||||
+ roothub_entry->phy = phy;
|
||||
+
|
||||
+ list_add_tail(&roothub_entry->list, list);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct platform_roothub *platform_roothub_init(struct device *dev)
|
||||
+{
|
||||
+ struct device_node *roothub_np, *port_np;
|
||||
+ struct platform_roothub *plat_roothub;
|
||||
+ int err;
|
||||
+
|
||||
+ roothub_np = usb_of_get_child_node(dev->of_node, ROOTHUB_PORTNUM);
|
||||
+ if (!of_device_is_available(roothub_np))
|
||||
+ return NULL;
|
||||
+
|
||||
+ plat_roothub = platform_roothub_alloc(dev);
|
||||
+ if (IS_ERR(plat_roothub))
|
||||
+ return plat_roothub;
|
||||
+
|
||||
+ for_each_available_child_of_node(roothub_np, port_np) {
|
||||
+ err = platform_roothub_add_phy(dev, port_np, "usb2-phy",
|
||||
+ &plat_roothub->list);
|
||||
+ if (err)
|
||||
+ return ERR_PTR(err);
|
||||
+
|
||||
+ err = platform_roothub_add_phy(dev, port_np, "usb3-phy",
|
||||
+ &plat_roothub->list);
|
||||
+ if (err)
|
||||
+ return ERR_PTR(err);
|
||||
+ }
|
||||
+
|
||||
+ return plat_roothub;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(platform_roothub_init);
|
||||
+
|
||||
+int platform_roothub_power_on(struct platform_roothub *plat_roothub)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+ struct list_head *head;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!plat_roothub)
|
||||
+ return 0;
|
||||
+
|
||||
+ head = &plat_roothub->list;
|
||||
+
|
||||
+ list_for_each_entry(roothub_entry, head, list) {
|
||||
+ err = phy_init(roothub_entry->phy);
|
||||
+ if (err)
|
||||
+ goto err_out;
|
||||
+
|
||||
+ err = phy_power_on(roothub_entry->phy);
|
||||
+ if (err) {
|
||||
+ phy_exit(roothub_entry->phy);
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_out:
|
||||
+ list_for_each_entry_continue_reverse(roothub_entry, head, list) {
|
||||
+ phy_power_off(roothub_entry->phy);
|
||||
+ phy_exit(roothub_entry->phy);
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(platform_roothub_power_on);
|
||||
+
|
||||
+void platform_roothub_power_off(struct platform_roothub *plat_roothub)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+
|
||||
+ if (!plat_roothub)
|
||||
+ return;
|
||||
+
|
||||
+ list_for_each_entry_reverse(roothub_entry, &plat_roothub->list, list) {
|
||||
+ phy_power_off(roothub_entry->phy);
|
||||
+ phy_exit(roothub_entry->phy);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(platform_roothub_power_off);
|
||||
diff --git a/drivers/usb/host/platform-roothub.h b/drivers/usb/host/platform-roothub.h
|
||||
new file mode 100644
|
||||
index 0000000000000..bde0bf299e3b5
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/host/platform-roothub.h
|
||||
@@ -0,0 +1,14 @@
|
||||
+#ifndef USB_HOST_PLATFORM_ROOTHUB_H
|
||||
+#define USB_HOST_PLATFORM_ROOTHUB_H
|
||||
+
|
||||
+struct phy;
|
||||
+struct device_node;
|
||||
+
|
||||
+struct platform_roothub;
|
||||
+
|
||||
+struct platform_roothub *platform_roothub_init(struct device *dev);
|
||||
+
|
||||
+int platform_roothub_power_on(struct platform_roothub *plat_roothub);
|
||||
+void platform_roothub_power_off(struct platform_roothub *plat_roothub);
|
||||
+
|
||||
+#endif /* USB_HOST_PLATFORM_ROOTHUB_H */
|
@ -1,7 +1,7 @@
|
||||
From 9bc414d9e18f8c9d39be44165b4926e2b2cdc1d9 Mon Sep 17 00:00:00 2001
|
||||
From 7a03fa7ed4d552f8e1397a18d9f0046f9c8a8076 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 16 Oct 2017 17:29:33 +0200
|
||||
Subject: [PATCH 14/39] clk: meson: gxbb: Add VPU and VAPB clockids
|
||||
Subject: [PATCH] clk: meson: gxbb: Add VPU and VAPB clockids
|
||||
|
||||
Add the clkids for the clocks feeding the Video Processing Unit.
|
||||
|
||||
@ -12,7 +12,7 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
2 files changed, 16 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
|
||||
index 5b1d4b3..aee6fbb 100644
|
||||
index 5b1d4b374d1c2..aee6fbba20043 100644
|
||||
--- a/drivers/clk/meson/gxbb.h
|
||||
+++ b/drivers/clk/meson/gxbb.h
|
||||
@@ -190,8 +190,12 @@
|
||||
@ -30,7 +30,7 @@ index 5b1d4b3..aee6fbb 100644
|
||||
/* include the CLKIDs that have been made part of the DT binding */
|
||||
#include <dt-bindings/clock/gxbb-clkc.h>
|
||||
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
|
||||
index 8c92528..8ba99a5 100644
|
||||
index 8c92528aa48ad..8ba99a5e3fd34 100644
|
||||
--- a/include/dt-bindings/clock/gxbb-clkc.h
|
||||
+++ b/include/dt-bindings/clock/gxbb-clkc.h
|
||||
@@ -114,5 +114,16 @@
|
||||
@ -50,6 +50,3 @@ index 8c92528..8ba99a5 100644
|
||||
+#define CLKID_VAPB 140
|
||||
|
||||
#endif /* __GXBB_CLKC_H */
|
||||
--
|
||||
2.7.4
|
||||
|
@ -1,7 +1,7 @@
|
||||
From a3b8b7bfd775fa521425c72856b4394fb6fec518 Mon Sep 17 00:00:00 2001
|
||||
From 89e3cdb01f2bf01810474984fd2c676a88973ac5 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 13 Oct 2017 14:38:37 +0200
|
||||
Subject: [PATCH 15/39] clk: meson: gxbb: Add VPU and VAPB clocks data
|
||||
Subject: [PATCH] clk: meson: gxbb: Add VPU and VAPB clocks data
|
||||
|
||||
The Amlogic Meson GX SoCs needs these two clocks to power up the
|
||||
VPU power domain.
|
||||
@ -15,7 +15,7 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
1 file changed, 292 insertions(+)
|
||||
|
||||
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
|
||||
index 92168348..86cb5af 100644
|
||||
index b2d1e8ed7152b..a71374464c92d 100644
|
||||
--- a/drivers/clk/meson/gxbb.c
|
||||
+++ b/drivers/clk/meson/gxbb.c
|
||||
@@ -1131,6 +1131,253 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = {
|
||||
@ -352,6 +352,3 @@ index 92168348..86cb5af 100644
|
||||
};
|
||||
|
||||
static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = {
|
||||
--
|
||||
2.7.4
|
||||
|
@ -1,7 +1,7 @@
|
||||
From 0689a4eaecae2831fe2cb614e102bb4ef43484a4 Mon Sep 17 00:00:00 2001
|
||||
From 434a32bab28ccf277229338b33849b24ace9cc35 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 13 Oct 2017 14:05:01 +0200
|
||||
Subject: [PATCH 18/39] reset: meson: add level reset support for GX SoC family
|
||||
Subject: [PATCH] reset: meson: add level reset support for GX SoC family
|
||||
|
||||
The Amlogic GX SoC family embeds alternate registers to drive the reset
|
||||
levels next to the pulse registers.
|
||||
@ -16,7 +16,7 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
1 file changed, 58 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c
|
||||
index a8b915e..f3b9d69 100644
|
||||
index a8b915eb8b581..f3b9d6989267e 100644
|
||||
--- a/drivers/reset/reset-meson.c
|
||||
+++ b/drivers/reset/reset-meson.c
|
||||
@@ -62,13 +62,16 @@
|
||||
@ -127,6 +127,3 @@ index a8b915e..f3b9d69 100644
|
||||
data->rcdev.of_node = pdev->dev.of_node;
|
||||
|
||||
return devm_reset_controller_register(&pdev->dev, &data->rcdev);
|
||||
--
|
||||
2.7.4
|
||||
|
@ -1,7 +1,7 @@
|
||||
From 58d5e73046ca5c28eb835c1a98f936193de5d4d0 Mon Sep 17 00:00:00 2001
|
||||
From 375dd688f29cc0e8da629b3896c86c7e263030ae Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 13 Oct 2017 17:05:00 +0200
|
||||
Subject: [PATCH 19/39] soc: amlogic: add Meson GX VPU Domains driver
|
||||
Subject: [PATCH] soc: amlogic: add Meson GX VPU Domains driver
|
||||
|
||||
The Video Processing Unit needs a specific Power Domain powering scheme
|
||||
this driver handles this as a PM Power Domain driver.
|
||||
@ -15,7 +15,7 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
create mode 100644 drivers/soc/amlogic/meson-gx-pwrc-vpu.c
|
||||
|
||||
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
|
||||
index 22acf06..c2c0513 100644
|
||||
index 22acf064531ff..c2c0513b18ff5 100644
|
||||
--- a/drivers/soc/amlogic/Kconfig
|
||||
+++ b/drivers/soc/amlogic/Kconfig
|
||||
@@ -8,5 +8,15 @@ config MESON_GX_SOCINFO
|
||||
@ -35,7 +35,7 @@ index 22acf06..c2c0513 100644
|
||||
|
||||
endmenu
|
||||
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
|
||||
index 3e85fc4..3174e93 100644
|
||||
index 3e85fc462c213..3174e93e72e9c 100644
|
||||
--- a/drivers/soc/amlogic/Makefile
|
||||
+++ b/drivers/soc/amlogic/Makefile
|
||||
@@ -1 +1,2 @@
|
||||
@ -43,7 +43,7 @@ index 3e85fc4..3174e93 100644
|
||||
+obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
|
||||
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
|
||||
new file mode 100644
|
||||
index 0000000..bf5190b
|
||||
index 0000000000000..bf5190b65ad9b
|
||||
--- /dev/null
|
||||
+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
|
||||
@@ -0,0 +1,234 @@
|
||||
@ -281,6 +281,3 @@ index 0000000..bf5190b
|
||||
+ },
|
||||
+};
|
||||
+builtin_platform_driver(meson_gx_pwrc_vpu_driver);
|
||||
--
|
||||
2.7.4
|
||||
|
@ -1,8 +1,8 @@
|
||||
From a2ae223bac1ad40a5bd7ee124b3af735ff445eb9 Mon Sep 17 00:00:00 2001
|
||||
From 6747193c223e945901f42d7e7bc1d3ddea663585 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 3 Nov 2017 16:43:24 +0100
|
||||
Subject: [PATCH 20/39] soc: amlogic: meson-gx-pwrc-vpu: fix power-off when
|
||||
powered by bootloader
|
||||
Subject: [PATCH] soc: amlogic: meson-gx-pwrc-vpu: fix power-off when powered
|
||||
by bootloader
|
||||
|
||||
In the case the VPU power domain has been powered on by the bootloader
|
||||
and no driver are attached to this power domain, the genpd will power it
|
||||
@ -19,7 +19,7 @@ Tested-by: Kevin Hilman <khilman@baylibre.com>
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
|
||||
index bf5190b..2bdeebc 100644
|
||||
index bf5190b65ad9b..2bdeebc48901d 100644
|
||||
--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
|
||||
+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
|
||||
@@ -34,7 +34,6 @@ struct meson_gx_pwrc_vpu {
|
||||
@ -100,6 +100,3 @@ index bf5190b..2bdeebc 100644
|
||||
}
|
||||
|
||||
static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
|
||||
--
|
||||
2.7.4
|
||||
|
@ -0,0 +1,128 @@
|
||||
From b940b2533f1bb3718ed50f4dc9091f8494e6f37a Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 8 Dec 2017 12:08:11 +0100
|
||||
Subject: [PATCH] net: phy: meson-gxl: detect LPA corruption
|
||||
|
||||
The purpose of this change is to fix the incorrect detection of the link
|
||||
partner (LP) advertised capabilities which sometimes happens with this PHY
|
||||
(roughly 1 time in a dozen)
|
||||
|
||||
This issue may cause the link to be negotiated at 10Mbps/Full or
|
||||
10Mbps/Half when 100MBps/Full is actually possible. In some case, the link
|
||||
is even completely broken and no communication is possible.
|
||||
|
||||
To detect the corruption, we must look for a magic undocumented bit in the
|
||||
WOL bank (hint given by the SoC vendor kernel) but this is not enough to
|
||||
cover all cases. We also have to look at the LPA ack. If the LP supports
|
||||
Aneg but did not ack our base code when aneg is completed, we assume
|
||||
something went wrong.
|
||||
|
||||
The detection of a corrupted LPA triggers a restart of the aneg process.
|
||||
This solves the problem but may take up to 6 retries to complete.
|
||||
|
||||
Fixes: 7334b3e47aee ("net: phy: Add Meson GXL Internal PHY driver")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/meson-gxl.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 73 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c
|
||||
index 1ea69b7585d9b..700007dd4be56 100644
|
||||
--- a/drivers/net/phy/meson-gxl.c
|
||||
+++ b/drivers/net/phy/meson-gxl.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/netdevice.h>
|
||||
+#include <linux/bitfield.h>
|
||||
|
||||
static int meson_gxl_config_init(struct phy_device *phydev)
|
||||
{
|
||||
@@ -50,6 +51,77 @@ static int meson_gxl_config_init(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* This function is provided to cope with the possible failures of this phy
|
||||
+ * during aneg process. When aneg fails, the PHY reports that aneg is done
|
||||
+ * but the value found in MII_LPA is wrong:
|
||||
+ * - Early failures: MII_LPA is just 0x0001. if MII_EXPANSION reports that
|
||||
+ * the link partner (LP) supports aneg but the LP never acked our base
|
||||
+ * code word, it is likely that we never sent it to begin with.
|
||||
+ * - Late failures: MII_LPA is filled with a value which seems to make sense
|
||||
+ * but it actually is not what the LP is advertising. It seems that we
|
||||
+ * can detect this using a magic bit in the WOL bank (reg 12 - bit 12).
|
||||
+ * If this particular bit is not set when aneg is reported being done,
|
||||
+ * it means MII_LPA is likely to be wrong.
|
||||
+ *
|
||||
+ * In both case, forcing a restart of the aneg process solve the problem.
|
||||
+ * When this failure happens, the first retry is usually successful but,
|
||||
+ * in some cases, it may take up to 6 retries to get a decent result
|
||||
+ */
|
||||
+int meson_gxl_read_status(struct phy_device *phydev)
|
||||
+{
|
||||
+ int ret, wol, lpa, exp;
|
||||
+
|
||||
+ if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
+ ret = genphy_aneg_done(phydev);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ else if (!ret)
|
||||
+ goto read_status_continue;
|
||||
+
|
||||
+ /* Need to access WOL bank, make sure the access is open */
|
||||
+ ret = phy_write(phydev, 0x14, 0x0000);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = phy_write(phydev, 0x14, 0x0400);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = phy_write(phydev, 0x14, 0x0000);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = phy_write(phydev, 0x14, 0x0400);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Request LPI_STATUS WOL register */
|
||||
+ ret = phy_write(phydev, 0x14, 0x8D80);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Read LPI_STATUS value */
|
||||
+ wol = phy_read(phydev, 0x15);
|
||||
+ if (wol < 0)
|
||||
+ return wol;
|
||||
+
|
||||
+ lpa = phy_read(phydev, MII_LPA);
|
||||
+ if (lpa < 0)
|
||||
+ return lpa;
|
||||
+
|
||||
+ exp = phy_read(phydev, MII_EXPANSION);
|
||||
+ if (exp < 0)
|
||||
+ return exp;
|
||||
+
|
||||
+ if (!(wol & BIT(12)) ||
|
||||
+ ((exp & EXPANSION_NWAY) && !(lpa & LPA_LPACK))) {
|
||||
+ /* Looks like aneg failed after all */
|
||||
+ phydev_dbg(phydev, "LPA corruption - aneg restart\n");
|
||||
+ return genphy_restart_aneg(phydev);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+read_status_continue:
|
||||
+ return genphy_read_status(phydev);
|
||||
+}
|
||||
+
|
||||
static struct phy_driver meson_gxl_phy[] = {
|
||||
{
|
||||
.phy_id = 0x01814400,
|
||||
@@ -60,7 +132,7 @@ static struct phy_driver meson_gxl_phy[] = {
|
||||
.config_init = meson_gxl_config_init,
|
||||
.config_aneg = genphy_config_aneg,
|
||||
.aneg_done = genphy_aneg_done,
|
||||
- .read_status = genphy_read_status,
|
||||
+ .read_status = meson_gxl_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
},
|
@ -0,0 +1,42 @@
|
||||
From 0b4f75b1bbf8c1bd22cf62b5100f930e75b9229e Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 3 Jan 2018 16:46:29 +0100
|
||||
Subject: [PATCH] net: stmmac: enable EEE in MII, GMII or RGMII only
|
||||
|
||||
Note in the databook - Section 4.4 - EEE :
|
||||
" The EEE feature is not supported when the MAC is configured to use the
|
||||
TBI, RTBI, SMII, RMII or SGMII single PHY interface. Even if the MAC
|
||||
supports multiple PHY interfaces, you should activate the EEE mode only
|
||||
when the MAC is operating with GMII, MII, or RGMII interface."
|
||||
|
||||
Applying this restriction solves a stability issue observed on Amlogic
|
||||
gxl platforms operating with RMII interface and the internal PHY.
|
||||
|
||||
Fixes: 83bf79b6bb64 ("stmmac: disable at run-time the EEE if not supported")
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Tested-by: Arnaud Patard <arnaud.patard@rtp-net.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
index 16bd509290844..294a19f0fc1be 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
@@ -364,9 +364,15 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
|
||||
bool stmmac_eee_init(struct stmmac_priv *priv)
|
||||
{
|
||||
struct net_device *ndev = priv->dev;
|
||||
+ int interface = priv->plat->interface;
|
||||
unsigned long flags;
|
||||
bool ret = false;
|
||||
|
||||
+ if ((interface != PHY_INTERFACE_MODE_MII) &&
|
||||
+ (interface != PHY_INTERFACE_MODE_GMII) &&
|
||||
+ !phy_interface_mode_is_rgmii(interface))
|
||||
+ goto out;
|
||||
+
|
||||
/* Using PCS we cannot dial with the phy registers at this stage
|
||||
* so we do not support extra feature like EEE.
|
||||
*/
|
@ -0,0 +1,82 @@
|
||||
From 20705cd911573220254947a6338b0804d1382720 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Tue, 23 Jan 2018 09:40:02 +0100
|
||||
Subject: [PATCH] media: rc: meson-ir: add timeout on idle
|
||||
|
||||
Meson hardware doesn't generate timeout events, so install a
|
||||
software timer to prevent "ghost keypresses".
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
drivers/media/rc/meson-ir.c | 22 ++++++++++++++++++++++
|
||||
1 file changed, 22 insertions(+)
|
||||
|
||||
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
|
||||
index f2204eb77e2ab..f34c5836412be 100644
|
||||
--- a/drivers/media/rc/meson-ir.c
|
||||
+++ b/drivers/media/rc/meson-ir.c
|
||||
@@ -69,6 +69,7 @@ struct meson_ir {
|
||||
void __iomem *reg;
|
||||
struct rc_dev *rc;
|
||||
spinlock_t lock;
|
||||
+ struct timer_list timeout_timer;
|
||||
};
|
||||
|
||||
static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg,
|
||||
@@ -98,6 +99,10 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
|
||||
rawir.pulse = !!(status & STATUS_IR_DEC_IN);
|
||||
|
||||
ir_raw_event_store(ir->rc, &rawir);
|
||||
+
|
||||
+ mod_timer(&ir->timeout_timer,
|
||||
+ jiffies + nsecs_to_jiffies(ir->rc->timeout));
|
||||
+
|
||||
ir_raw_event_handle(ir->rc);
|
||||
|
||||
spin_unlock(&ir->lock);
|
||||
@@ -105,6 +110,17 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
+static void meson_ir_timeout_timer(struct timer_list *t)
|
||||
+{
|
||||
+ struct meson_ir *ir = from_timer(ir, t, timeout_timer);
|
||||
+ DEFINE_IR_RAW_EVENT(rawir);
|
||||
+
|
||||
+ rawir.timeout = true;
|
||||
+ rawir.duration = ir->rc->timeout;
|
||||
+ ir_raw_event_store(ir->rc, &rawir);
|
||||
+ ir_raw_event_handle(ir->rc);
|
||||
+}
|
||||
+
|
||||
static int meson_ir_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -145,7 +161,9 @@ static int meson_ir_probe(struct platform_device *pdev)
|
||||
ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
|
||||
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
|
||||
ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
|
||||
+ ir->rc->min_timeout = 1;
|
||||
ir->rc->timeout = MS_TO_NS(200);
|
||||
+ ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
|
||||
ir->rc->driver_name = DRIVER_NAME;
|
||||
|
||||
spin_lock_init(&ir->lock);
|
||||
@@ -157,6 +175,8 @@ static int meson_ir_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ timer_setup(&ir->timeout_timer, meson_ir_timeout_timer, 0);
|
||||
+
|
||||
ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request irq\n");
|
||||
@@ -198,6 +218,8 @@ static int meson_ir_remove(struct platform_device *pdev)
|
||||
meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0);
|
||||
spin_unlock_irqrestore(&ir->lock, flags);
|
||||
|
||||
+ del_timer_sync(&ir->timeout_timer);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-04-28 19:24:56.090524456 +0200
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts 2018-04-29 23:09:48.559371108 +0200
|
||||
@@ -409,6 +409,7 @@
|
||||
&usb0_phy {
|
||||
status = "okay";
|
||||
phy-supply = <&usb_otg_pwr>;
|
||||
+ dr_mode = "otg";
|
||||
};
|
||||
|
||||
&usb1_phy {
|
||||
@@ -418,6 +419,7 @@
|
||||
|
||||
&usb0 {
|
||||
status = "okay";
|
||||
+ dr_mode = "host";
|
||||
};
|
||||
|
||||
&usb1 {
|
||||
|
||||
--- a/drivers/phy/amlogic/phy-meson8b-usb2.c 2018-04-28 19:22:57.420144229 +0200
|
||||
+++ b/drivers/phy/amlogic/phy-meson8b-usb2.c 2018-04-29 23:13:57.136515043 +0200
|
||||
@@ -113,6 +113,7 @@
|
||||
struct phy_meson8b_usb2_priv {
|
||||
void __iomem *regs;
|
||||
enum usb_dr_mode dr_mode;
|
||||
+ enum usb_dr_mode phy_mode;
|
||||
struct clk *clk_usb_general;
|
||||
struct clk *clk_usb;
|
||||
struct reset_control *reset;
|
||||
@@ -181,7 +182,7 @@
|
||||
phy_meson8b_usb2_mask_bits(priv, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT,
|
||||
REG_CTRL_SOF_TOGGLE_OUT);
|
||||
|
||||
- if (priv->dr_mode == USB_DR_MODE_HOST) {
|
||||
+ if (priv->phy_mode == USB_DR_MODE_HOST) {
|
||||
phy_meson8b_usb2_mask_bits(priv, REG_ADP_BC,
|
||||
REG_ADP_BC_ACA_ENABLE,
|
||||
REG_ADP_BC_ACA_ENABLE);
|
||||
@@ -251,6 +252,11 @@
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ priv->phy_mode = usb_get_dr_mode(&pdev->dev);
|
||||
+ if (priv->phy_mode == USB_DR_MODE_UNKNOWN) {
|
||||
+ priv->phy_mode = priv->dr_mode;
|
||||
+ }
|
||||
+
|
||||
phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
|
||||
if (IS_ERR(phy)) {
|
||||
dev_err(&pdev->dev, "failed to create PHY\n");
|
@ -0,0 +1,103 @@
|
||||
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
|
||||
index 674b35f40..3497cabda 100644
|
||||
--- a/drivers/mailbox/mailbox.c
|
||||
+++ b/drivers/mailbox/mailbox.c
|
||||
@@ -26,6 +26,8 @@
|
||||
static LIST_HEAD(mbox_cons);
|
||||
static DEFINE_MUTEX(con_mutex);
|
||||
|
||||
+static void poll_txdone(struct timer_list *t);
|
||||
+
|
||||
static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
|
||||
{
|
||||
int idx;
|
||||
@@ -86,8 +88,7 @@ static void msg_submit(struct mbox_chan *chan)
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
if (!err && (chan->txdone_method & TXDONE_BY_POLL))
|
||||
- /* kick start the timer immediately to avoid delays */
|
||||
- hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
|
||||
+ poll_txdone(&chan->mbox->poll);
|
||||
}
|
||||
|
||||
static void tx_tick(struct mbox_chan *chan, int r)
|
||||
@@ -114,10 +115,9 @@ static void tx_tick(struct mbox_chan *chan, int r)
|
||||
complete(&chan->tx_complete);
|
||||
}
|
||||
|
||||
-static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
||||
+static void poll_txdone(struct timer_list *t)
|
||||
{
|
||||
- struct mbox_controller *mbox =
|
||||
- container_of(hrtimer, struct mbox_controller, poll_hrt);
|
||||
+ struct mbox_controller *mbox = from_timer(mbox, t, poll);
|
||||
bool txdone, resched = false;
|
||||
int i;
|
||||
|
||||
@@ -133,11 +133,9 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
||||
}
|
||||
}
|
||||
|
||||
- if (resched) {
|
||||
- hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period));
|
||||
- return HRTIMER_RESTART;
|
||||
- }
|
||||
- return HRTIMER_NORESTART;
|
||||
+ if (resched)
|
||||
+ mod_timer(&mbox->poll, jiffies +
|
||||
+ msecs_to_jiffies(mbox->txpoll_period));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,9 +464,7 @@ int mbox_controller_register(struct mbox_controller *mbox)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC,
|
||||
- HRTIMER_MODE_REL);
|
||||
- mbox->poll_hrt.function = txdone_hrtimer;
|
||||
+ timer_setup(&mbox->poll, &poll_txdone, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < mbox->num_chans; i++) {
|
||||
@@ -510,7 +506,7 @@ void mbox_controller_unregister(struct mbox_controller *mbox)
|
||||
mbox_free_channel(&mbox->chans[i]);
|
||||
|
||||
if (mbox->txdone_poll)
|
||||
- hrtimer_cancel(&mbox->poll_hrt);
|
||||
+ del_timer_sync(&mbox->poll);
|
||||
|
||||
mutex_unlock(&con_mutex);
|
||||
}
|
||||
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
|
||||
index 74deadb42..68c424544 100644
|
||||
--- a/include/linux/mailbox_controller.h
|
||||
+++ b/include/linux/mailbox_controller.h
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
-#include <linux/hrtimer.h>
|
||||
+#include <linux/timer.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
@@ -67,8 +67,7 @@ struct mbox_chan_ops {
|
||||
* @txpoll_period: If 'txdone_poll' is in effect, the API polls for
|
||||
* last TX's status after these many millisecs
|
||||
* @of_xlate: Controller driver specific mapping of channel via DT
|
||||
- * @poll_hrt: API private. hrtimer used to poll for TXDONE on all
|
||||
- * channels.
|
||||
+ * @poll: API private. Used to poll for TXDONE on all channels.
|
||||
* @node: API private. To hook into list of controllers.
|
||||
*/
|
||||
struct mbox_controller {
|
||||
@@ -82,7 +81,7 @@ struct mbox_controller {
|
||||
struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
|
||||
const struct of_phandle_args *sp);
|
||||
/* Internal to API */
|
||||
- struct hrtimer poll_hrt;
|
||||
+ struct timer_list poll;
|
||||
struct list_head node;
|
||||
};
|
||||
|
@ -0,0 +1,30 @@
|
||||
From 997decfb6aeaa9be41ff557741845bb9fb4bf5bc Mon Sep 17 00:00:00 2001
|
||||
From: Allen Pais <allen.lkml@gmail.com>
|
||||
Date: Thu, 21 Sep 2017 22:35:18 +0530
|
||||
Subject: [PATCH] drivers: net: stmmac: use setup_timer() helper.
|
||||
|
||||
Use setup_timer function instead of initializing timer with the
|
||||
function and data fields.
|
||||
|
||||
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
index 1763e48c84e20..f41661a04f237 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
@@ -2217,10 +2217,8 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)
|
||||
{
|
||||
priv->tx_coal_frames = STMMAC_TX_FRAMES;
|
||||
priv->tx_coal_timer = STMMAC_COAL_TX_TIMER;
|
||||
- init_timer(&priv->txtimer);
|
||||
+ setup_timer(&priv->txtimer, stmmac_tx_timer, (unsigned long)priv);
|
||||
priv->txtimer.expires = STMMAC_COAL_TIMER(priv->tx_coal_timer);
|
||||
- priv->txtimer.data = (unsigned long)priv;
|
||||
- priv->txtimer.function = stmmac_tx_timer;
|
||||
add_timer(&priv->txtimer);
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
From c778c32118167adcfe6b40063c49bfeac6bc1cf1 Mon Sep 17 00:00:00 2001
|
||||
From: Christos Gkekas <chris.gekas@gmail.com>
|
||||
Date: Sun, 8 Oct 2017 20:13:49 +0100
|
||||
Subject: [PATCH] net: ethernet: stmmac: Clean up dead code
|
||||
|
||||
Many macros in dwmac-ipq806x are unused and should be removed.
|
||||
Moreover gmac->id is an unsigned variable and therefore checking
|
||||
whether it is less than zero is redundant.
|
||||
|
||||
Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 14 +-------------
|
||||
1 file changed, 1 insertion(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
|
||||
index 866444b6c82fa..2c6d7c69c8f74 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
|
||||
@@ -51,15 +51,11 @@
|
||||
#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1
|
||||
#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0)
|
||||
|
||||
-#define NSS_COMMON_MACSEC_CTL 0x28
|
||||
-#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
|
||||
-
|
||||
#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4))
|
||||
#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19)
|
||||
#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16)
|
||||
#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8
|
||||
#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0
|
||||
-#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f
|
||||
|
||||
#define NSS_COMMON_CLK_DIV_RGMII_1000 1
|
||||
#define NSS_COMMON_CLK_DIV_RGMII_100 9
|
||||
@@ -68,9 +64,6 @@
|
||||
#define NSS_COMMON_CLK_DIV_SGMII_100 4
|
||||
#define NSS_COMMON_CLK_DIV_SGMII_10 49
|
||||
|
||||
-#define QSGMII_PCS_MODE_CTL 0x68
|
||||
-#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7)
|
||||
-
|
||||
#define QSGMII_PCS_CAL_LCKDT_CTL 0x120
|
||||
#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
|
||||
|
||||
@@ -83,15 +76,10 @@
|
||||
#define QSGMII_PHY_TX_DRIVER_EN BIT(3)
|
||||
#define QSGMII_PHY_QSGMII_EN BIT(7)
|
||||
#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12
|
||||
-#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7
|
||||
#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18
|
||||
-#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3
|
||||
#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20
|
||||
-#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3
|
||||
#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22
|
||||
-#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3
|
||||
#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28
|
||||
-#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf
|
||||
|
||||
struct ipq806x_gmac {
|
||||
struct platform_device *pdev;
|
||||
@@ -217,7 +205,7 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
|
||||
* code and keep it consistent with the Linux convention, we'll number
|
||||
* them from 0 to 3 here.
|
||||
*/
|
||||
- if (gmac->id < 0 || gmac->id > 3) {
|
||||
+ if (gmac->id > 3) {
|
||||
dev_err(dev, "invalid gmac id\n");
|
||||
return -EINVAL;
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
From 52a76235d0c4dd259cd0df503afed4757c04ba1d Mon Sep 17 00:00:00 2001
|
||||
From: Jose Abreu <Jose.Abreu@synopsys.com>
|
||||
Date: Fri, 13 Oct 2017 10:58:36 +0100
|
||||
Subject: [PATCH] net: stmmac: Use correct values in TQS/RQS fields
|
||||
|
||||
Currently we are using all the available fifo size in RQS and
|
||||
TQS fields. This will not work correctly in multi-queues IP's
|
||||
because total fifo size must be splitted to the enabled queues.
|
||||
|
||||
Correct this by computing the available fifo size per queue and
|
||||
setting the right value in TQS and RQS fields.
|
||||
|
||||
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
|
||||
Cc: David S. Miller <davem@davemloft.net>
|
||||
Cc: Joao Pinto <jpinto@synopsys.com>
|
||||
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
Cc: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/common.h | 3 ++-
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 15 +++++++++------
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 22 ++++++++++++++++++++--
|
||||
3 files changed, 31 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
index e82b4b70b7be3..c26c8a7f957f5 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
@@ -443,7 +443,8 @@ struct stmmac_dma_ops {
|
||||
int rxfifosz);
|
||||
void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
|
||||
int fifosz);
|
||||
- void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel);
|
||||
+ void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel,
|
||||
+ int fifosz);
|
||||
/* To track extra statistic (if supported) */
|
||||
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr);
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
|
||||
index e84831e1b63b3..898849bbc7d44 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
|
||||
@@ -271,9 +271,10 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
}
|
||||
|
||||
static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
- u32 channel)
|
||||
+ u32 channel, int fifosz)
|
||||
{
|
||||
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
|
||||
+ unsigned int tqs = fifosz / 256 - 1;
|
||||
|
||||
if (mode == SF_DMA_MODE) {
|
||||
pr_debug("GMAC: enable TX store and forward mode\n");
|
||||
@@ -306,12 +307,14 @@ static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
* For an IP with DWC_EQOS_NUM_TXQ > 1, the fields TXQEN and TQS are R/W
|
||||
* with reset values: TXQEN off, TQS 256 bytes.
|
||||
*
|
||||
- * Write the bits in both cases, since it will have no effect when RO.
|
||||
- * For DWC_EQOS_NUM_TXQ > 1, the top bits in MTL_OP_MODE_TQS_MASK might
|
||||
- * be RO, however, writing the whole TQS field will result in a value
|
||||
- * equal to DWC_EQOS_TXFIFO_SIZE, just like for DWC_EQOS_NUM_TXQ == 1.
|
||||
+ * TXQEN must be written for multi-channel operation and TQS must
|
||||
+ * reflect the available fifo size per queue (total fifo size / number
|
||||
+ * of enabled queues).
|
||||
*/
|
||||
- mtl_tx_op |= MTL_OP_MODE_TXQEN | MTL_OP_MODE_TQS_MASK;
|
||||
+ mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
+ mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK;
|
||||
+ mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT;
|
||||
+
|
||||
writel(mtl_tx_op, ioaddr + MTL_CHAN_TX_OP_MODE(channel));
|
||||
}
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
index f41661a04f237..edf245b8bce32 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
@@ -1750,12 +1750,19 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
|
||||
u32 rx_channels_count = priv->plat->rx_queues_to_use;
|
||||
u32 tx_channels_count = priv->plat->tx_queues_to_use;
|
||||
int rxfifosz = priv->plat->rx_fifo_size;
|
||||
+ int txfifosz = priv->plat->tx_fifo_size;
|
||||
u32 txmode = 0;
|
||||
u32 rxmode = 0;
|
||||
u32 chan = 0;
|
||||
|
||||
if (rxfifosz == 0)
|
||||
rxfifosz = priv->dma_cap.rx_fifo_size;
|
||||
+ if (txfifosz == 0)
|
||||
+ txfifosz = priv->dma_cap.tx_fifo_size;
|
||||
+
|
||||
+ /* Adjust for real per queue fifo size */
|
||||
+ rxfifosz /= rx_channels_count;
|
||||
+ txfifosz /= tx_channels_count;
|
||||
|
||||
if (priv->plat->force_thresh_dma_mode) {
|
||||
txmode = tc;
|
||||
@@ -1783,7 +1790,8 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
|
||||
rxfifosz);
|
||||
|
||||
for (chan = 0; chan < tx_channels_count; chan++)
|
||||
- priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan);
|
||||
+ priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
|
||||
+ txfifosz);
|
||||
} else {
|
||||
priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
|
||||
rxfifosz);
|
||||
@@ -1946,15 +1954,25 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan)
|
||||
static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
|
||||
u32 rxmode, u32 chan)
|
||||
{
|
||||
+ u32 rx_channels_count = priv->plat->rx_queues_to_use;
|
||||
+ u32 tx_channels_count = priv->plat->tx_queues_to_use;
|
||||
int rxfifosz = priv->plat->rx_fifo_size;
|
||||
+ int txfifosz = priv->plat->tx_fifo_size;
|
||||
|
||||
if (rxfifosz == 0)
|
||||
rxfifosz = priv->dma_cap.rx_fifo_size;
|
||||
+ if (txfifosz == 0)
|
||||
+ txfifosz = priv->dma_cap.tx_fifo_size;
|
||||
+
|
||||
+ /* Adjust for real per queue fifo size */
|
||||
+ rxfifosz /= rx_channels_count;
|
||||
+ txfifosz /= tx_channels_count;
|
||||
|
||||
if (priv->synopsys_id >= DWMAC_CORE_4_00) {
|
||||
priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
|
||||
rxfifosz);
|
||||
- priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan);
|
||||
+ priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
|
||||
+ txfifosz);
|
||||
} else {
|
||||
priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
|
||||
rxfifosz);
|
@ -0,0 +1,160 @@
|
||||
From a0daae13776994cf90e9a7bc81cd8e4ad3959093 Mon Sep 17 00:00:00 2001
|
||||
From: Jose Abreu <Jose.Abreu@synopsys.com>
|
||||
Date: Fri, 13 Oct 2017 10:58:37 +0100
|
||||
Subject: [PATCH] net: stmmac: Disable flow ctrl for RX AVB queues and really
|
||||
enable TX AVB queues
|
||||
|
||||
Flow control must be disabled for AVB enabled queues and TX
|
||||
AVB queues must be enabled by setting BIT(2) of TXQEN.
|
||||
|
||||
Correct this by passing the queue mode to DMA callbacks
|
||||
and by checking in these functions wether we are in AVB
|
||||
performing the necessary adjustments.
|
||||
|
||||
Signed-off-by: Jose Abreu <joabreu@synopsys.com>
|
||||
Cc: David S. Miller <davem@davemloft.net>
|
||||
Cc: Joao Pinto <jpinto@synopsys.com>
|
||||
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
Cc: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/common.h | 4 ++--
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 2 ++
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 16 +++++++++++-----
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 21 +++++++++++++++------
|
||||
4 files changed, 30 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
index c26c8a7f957f5..e1e5ac0537606 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
@@ -442,9 +442,9 @@ struct stmmac_dma_ops {
|
||||
void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
|
||||
int rxfifosz);
|
||||
void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
|
||||
- int fifosz);
|
||||
+ int fifosz, u8 qmode);
|
||||
void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel,
|
||||
- int fifosz);
|
||||
+ int fifosz, u8 qmode);
|
||||
/* To track extra statistic (if supported) */
|
||||
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr);
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
index d74cedf2a3975..aeda3ab2d761c 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
@@ -225,6 +225,8 @@ enum power_event {
|
||||
#define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x38)
|
||||
|
||||
#define MTL_OP_MODE_RSF BIT(5)
|
||||
+#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2)
|
||||
+#define MTL_OP_MODE_TXQEN_AV BIT(2)
|
||||
#define MTL_OP_MODE_TXQEN BIT(3)
|
||||
#define MTL_OP_MODE_TSF BIT(1)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
|
||||
index 898849bbc7d44..c110f6850ffa3 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
|
||||
@@ -191,7 +191,7 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan)
|
||||
}
|
||||
|
||||
static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
- u32 channel, int fifosz)
|
||||
+ u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
unsigned int rqs = fifosz / 256 - 1;
|
||||
u32 mtl_rx_op, mtl_rx_int;
|
||||
@@ -218,8 +218,10 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
|
||||
mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
|
||||
|
||||
- /* enable flow control only if each channel gets 4 KiB or more FIFO */
|
||||
- if (fifosz >= 4096) {
|
||||
+ /* Enable flow control only if each channel gets 4 KiB or more FIFO and
|
||||
+ * only if channel is not an AVB channel.
|
||||
+ */
|
||||
+ if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
|
||||
unsigned int rfd, rfa;
|
||||
|
||||
mtl_rx_op |= MTL_OP_MODE_EHFC;
|
||||
@@ -271,7 +273,7 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
}
|
||||
|
||||
static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
- u32 channel, int fifosz)
|
||||
+ u32 channel, int fifosz, u8 qmode)
|
||||
{
|
||||
u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
|
||||
unsigned int tqs = fifosz / 256 - 1;
|
||||
@@ -311,7 +313,11 @@ static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
|
||||
* reflect the available fifo size per queue (total fifo size / number
|
||||
* of enabled queues).
|
||||
*/
|
||||
- mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
+ mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
|
||||
+ if (qmode != MTL_QUEUE_AVB)
|
||||
+ mtl_tx_op |= MTL_OP_MODE_TXQEN;
|
||||
+ else
|
||||
+ mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
|
||||
mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK;
|
||||
mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT;
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
index edf245b8bce32..0e1b0a3d7b766 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
@@ -1754,6 +1754,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
|
||||
u32 txmode = 0;
|
||||
u32 rxmode = 0;
|
||||
u32 chan = 0;
|
||||
+ u8 qmode = 0;
|
||||
|
||||
if (rxfifosz == 0)
|
||||
rxfifosz = priv->dma_cap.rx_fifo_size;
|
||||
@@ -1785,13 +1786,19 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
|
||||
|
||||
/* configure all channels */
|
||||
if (priv->synopsys_id >= DWMAC_CORE_4_00) {
|
||||
- for (chan = 0; chan < rx_channels_count; chan++)
|
||||
+ for (chan = 0; chan < rx_channels_count; chan++) {
|
||||
+ qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
|
||||
+
|
||||
priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
|
||||
- rxfifosz);
|
||||
+ rxfifosz, qmode);
|
||||
+ }
|
||||
+
|
||||
+ for (chan = 0; chan < tx_channels_count; chan++) {
|
||||
+ qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
|
||||
|
||||
- for (chan = 0; chan < tx_channels_count; chan++)
|
||||
priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
|
||||
- txfifosz);
|
||||
+ txfifosz, qmode);
|
||||
+ }
|
||||
} else {
|
||||
priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
|
||||
rxfifosz);
|
||||
@@ -1954,6 +1961,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan)
|
||||
static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
|
||||
u32 rxmode, u32 chan)
|
||||
{
|
||||
+ u8 rxqmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
|
||||
+ u8 txqmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
|
||||
u32 rx_channels_count = priv->plat->rx_queues_to_use;
|
||||
u32 tx_channels_count = priv->plat->tx_queues_to_use;
|
||||
int rxfifosz = priv->plat->rx_fifo_size;
|
||||
@@ -1970,9 +1979,9 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
|
||||
|
||||
if (priv->synopsys_id >= DWMAC_CORE_4_00) {
|
||||
priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
|
||||
- rxfifosz);
|
||||
+ rxfifosz, rxqmode);
|
||||
priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
|
||||
- txfifosz);
|
||||
+ txfifosz, txqmode);
|
||||
} else {
|
||||
priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
|
||||
rxfifosz);
|
@ -0,0 +1,90 @@
|
||||
From abec4be3ee68c8572adb39da68fbfd86e63daa84 Mon Sep 17 00:00:00 2001
|
||||
From: Kees Cook <keescook@chromium.org>
|
||||
Date: Mon, 16 Oct 2017 17:29:00 -0700
|
||||
Subject: [PATCH] net: ethernet: stmmac: Convert timers to use timer_setup()
|
||||
|
||||
In preparation for unconditionally passing the struct timer_list pointer to
|
||||
all timer callbacks, switch to using the new timer_setup() and from_timer()
|
||||
to pass the timer pointer explicitly.
|
||||
|
||||
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
Cc: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
Cc: netdev@vger.kernel.org
|
||||
Signed-off-by: Kees Cook <keescook@chromium.org>
|
||||
Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c | 22 ++++++++++------------
|
||||
1 file changed, 10 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
|
||||
index 6a9c954492f22..8b50afcdb52df 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c
|
||||
@@ -118,10 +118,9 @@ int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs)
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static void pcs_link_timer_callback(unsigned long data)
|
||||
+static void pcs_link_timer_callback(struct tse_pcs *pcs)
|
||||
{
|
||||
u16 val = 0;
|
||||
- struct tse_pcs *pcs = (struct tse_pcs *)data;
|
||||
void __iomem *tse_pcs_base = pcs->tse_pcs_base;
|
||||
void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
|
||||
|
||||
@@ -138,12 +137,11 @@ static void pcs_link_timer_callback(unsigned long data)
|
||||
}
|
||||
}
|
||||
|
||||
-static void auto_nego_timer_callback(unsigned long data)
|
||||
+static void auto_nego_timer_callback(struct tse_pcs *pcs)
|
||||
{
|
||||
u16 val = 0;
|
||||
u16 speed = 0;
|
||||
u16 duplex = 0;
|
||||
- struct tse_pcs *pcs = (struct tse_pcs *)data;
|
||||
void __iomem *tse_pcs_base = pcs->tse_pcs_base;
|
||||
void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
|
||||
|
||||
@@ -201,14 +199,14 @@ static void auto_nego_timer_callback(unsigned long data)
|
||||
}
|
||||
}
|
||||
|
||||
-static void aneg_link_timer_callback(unsigned long data)
|
||||
+static void aneg_link_timer_callback(struct timer_list *t)
|
||||
{
|
||||
- struct tse_pcs *pcs = (struct tse_pcs *)data;
|
||||
+ struct tse_pcs *pcs = from_timer(pcs, t, aneg_link_timer);
|
||||
|
||||
if (pcs->autoneg == AUTONEG_ENABLE)
|
||||
- auto_nego_timer_callback(data);
|
||||
+ auto_nego_timer_callback(pcs);
|
||||
else if (pcs->autoneg == AUTONEG_DISABLE)
|
||||
- pcs_link_timer_callback(data);
|
||||
+ pcs_link_timer_callback(pcs);
|
||||
}
|
||||
|
||||
void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
|
||||
@@ -237,8 +235,8 @@ void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
|
||||
|
||||
tse_pcs_reset(tse_pcs_base, pcs);
|
||||
|
||||
- setup_timer(&pcs->aneg_link_timer,
|
||||
- aneg_link_timer_callback, (unsigned long)pcs);
|
||||
+ timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
|
||||
+ 0);
|
||||
mod_timer(&pcs->aneg_link_timer, jiffies +
|
||||
msecs_to_jiffies(AUTONEGO_LINK_TIMER));
|
||||
} else if (phy_dev->autoneg == AUTONEG_DISABLE) {
|
||||
@@ -270,8 +268,8 @@ void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
|
||||
|
||||
tse_pcs_reset(tse_pcs_base, pcs);
|
||||
|
||||
- setup_timer(&pcs->aneg_link_timer,
|
||||
- aneg_link_timer_callback, (unsigned long)pcs);
|
||||
+ timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
|
||||
+ 0);
|
||||
mod_timer(&pcs->aneg_link_timer, jiffies +
|
||||
msecs_to_jiffies(AUTONEGO_LINK_TIMER));
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
From b5beecb580376cd8d959eb990abece6a748a3ce3 Mon Sep 17 00:00:00 2001
|
||||
From: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Date: Tue, 24 Oct 2017 19:57:12 +0200
|
||||
Subject: [PATCH] net: stmmac: snps, dwmac-mdio MDIOs are automatically
|
||||
registered
|
||||
|
||||
stmmac bindings docs said that its mdio node must have
|
||||
compatible = "snps,dwmac-mdio";
|
||||
Since dwmac-sun8i does not have any good reasons to not doing it, all
|
||||
their MDIO node must have it.
|
||||
|
||||
Since these compatible is automatically registered, dwmac-sun8i compatible
|
||||
does not need to be in need_mdio_ids.
|
||||
|
||||
Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 4 ----
|
||||
1 file changed, 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
|
||||
index 8a280b48e3a9f..9e616da0745d6 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
|
||||
@@ -311,10 +311,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
|
||||
bool mdio = true;
|
||||
static const struct of_device_id need_mdio_ids[] = {
|
||||
{ .compatible = "snps,dwc-qos-ethernet-4.10" },
|
||||
- { .compatible = "allwinner,sun8i-a83t-emac" },
|
||||
- { .compatible = "allwinner,sun8i-h3-emac" },
|
||||
- { .compatible = "allwinner,sun8i-v3s-emac" },
|
||||
- { .compatible = "allwinner,sun50i-a64-emac" },
|
||||
{},
|
||||
};
|
||||
|
@ -0,0 +1,510 @@
|
||||
From 634db83b82658f4641d8026e340c6027cf74a6bb Mon Sep 17 00:00:00 2001
|
||||
From: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Date: Tue, 24 Oct 2017 19:57:13 +0200
|
||||
Subject: [PATCH] net: stmmac: dwmac-sun8i: Handle integrated/external MDIOs
|
||||
|
||||
The Allwinner H3 SoC have two distinct MDIO bus, only one could be
|
||||
active at the same time.
|
||||
The selection of the active MDIO bus are done via some bits in the EMAC
|
||||
register of the system controller.
|
||||
|
||||
This patch implement this MDIO switch via a custom MDIO-mux.
|
||||
|
||||
Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 +
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 353 ++++++++++++++--------
|
||||
2 files changed, 224 insertions(+), 130 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
|
||||
index 97035766c291b..e28c0d2c58e91 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
|
||||
@@ -159,6 +159,7 @@ config DWMAC_SUN8I
|
||||
tristate "Allwinner sun8i GMAC support"
|
||||
default ARCH_SUNXI
|
||||
depends on OF && (ARCH_SUNXI || COMPILE_TEST)
|
||||
+ select MDIO_BUS_MUX
|
||||
---help---
|
||||
Support for Allwinner H3 A83T A64 EMAC ethernet controllers.
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
index 39c2122a4f269..b3eb344bb158d 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/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
+#include <linux/mdio-mux.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -41,14 +42,14 @@
|
||||
* This value is used for disabling properly EMAC
|
||||
* and used as a good starting value in case of the
|
||||
* boot process(uboot) leave some stuff.
|
||||
- * @internal_phy: Does the MAC embed an internal PHY
|
||||
+ * @soc_has_internal_phy: Does the MAC embed an internal PHY
|
||||
* @support_mii: Does the MAC handle MII
|
||||
* @support_rmii: Does the MAC handle RMII
|
||||
* @support_rgmii: Does the MAC handle RGMII
|
||||
*/
|
||||
struct emac_variant {
|
||||
u32 default_syscon_value;
|
||||
- int internal_phy;
|
||||
+ bool soc_has_internal_phy;
|
||||
bool support_mii;
|
||||
bool support_rmii;
|
||||
bool support_rgmii;
|
||||
@@ -61,7 +62,8 @@ struct emac_variant {
|
||||
* @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
|
||||
- * @use_internal_phy: Does the current PHY choice imply using the internal PHY
|
||||
+ * @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;
|
||||
@@ -70,12 +72,13 @@ struct sunxi_priv_data {
|
||||
struct reset_control *rst_ephy;
|
||||
const struct emac_variant *variant;
|
||||
struct regmap *regmap;
|
||||
- bool use_internal_phy;
|
||||
+ bool internal_phy_powered;
|
||||
+ void *mux_handle;
|
||||
};
|
||||
|
||||
static const struct emac_variant emac_variant_h3 = {
|
||||
.default_syscon_value = 0x58000,
|
||||
- .internal_phy = PHY_INTERFACE_MODE_MII,
|
||||
+ .soc_has_internal_phy = true,
|
||||
.support_mii = true,
|
||||
.support_rmii = true,
|
||||
.support_rgmii = true
|
||||
@@ -83,20 +86,20 @@ static const struct emac_variant emac_variant_h3 = {
|
||||
|
||||
static const struct emac_variant emac_variant_v3s = {
|
||||
.default_syscon_value = 0x38000,
|
||||
- .internal_phy = PHY_INTERFACE_MODE_MII,
|
||||
+ .soc_has_internal_phy = true,
|
||||
.support_mii = true
|
||||
};
|
||||
|
||||
static const struct emac_variant emac_variant_a83t = {
|
||||
.default_syscon_value = 0,
|
||||
- .internal_phy = 0,
|
||||
+ .soc_has_internal_phy = false,
|
||||
.support_mii = true,
|
||||
.support_rgmii = true
|
||||
};
|
||||
|
||||
static const struct emac_variant emac_variant_a64 = {
|
||||
.default_syscon_value = 0,
|
||||
- .internal_phy = 0,
|
||||
+ .soc_has_internal_phy = false,
|
||||
.support_mii = true,
|
||||
.support_rmii = true,
|
||||
.support_rgmii = true
|
||||
@@ -195,6 +198,9 @@ static const struct emac_variant emac_variant_a64 = {
|
||||
#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */
|
||||
#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
|
||||
#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
|
||||
+#define H3_EPHY_MUX_MASK (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT)
|
||||
+#define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID 1
|
||||
+#define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID 2
|
||||
|
||||
/* H3/A64 specific bits */
|
||||
#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */
|
||||
@@ -634,6 +640,159 @@ static int sun8i_dwmac_reset(struct stmmac_priv *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/* Search in mdio-mux node for internal PHY node and get its clk/reset */
|
||||
+static int get_ephy_nodes(struct stmmac_priv *priv)
|
||||
+{
|
||||
+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
|
||||
+ struct device_node *mdio_mux, *iphynode;
|
||||
+ struct device_node *mdio_internal;
|
||||
+ int ret;
|
||||
+
|
||||
+ mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
|
||||
+ if (!mdio_mux) {
|
||||
+ dev_err(priv->device, "Cannot get mdio-mux node\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ mdio_internal = of_find_compatible_node(mdio_mux, NULL,
|
||||
+ "allwinner,sun8i-h3-mdio-internal");
|
||||
+ if (!mdio_internal) {
|
||||
+ dev_err(priv->device, "Cannot get internal_mdio node\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* Seek for internal PHY */
|
||||
+ for_each_child_of_node(mdio_internal, iphynode) {
|
||||
+ gmac->ephy_clk = of_clk_get(iphynode, 0);
|
||||
+ if (IS_ERR(gmac->ephy_clk))
|
||||
+ continue;
|
||||
+ gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL);
|
||||
+ if (IS_ERR(gmac->rst_ephy)) {
|
||||
+ ret = PTR_ERR(gmac->rst_ephy);
|
||||
+ if (ret == -EPROBE_DEFER)
|
||||
+ return ret;
|
||||
+ continue;
|
||||
+ }
|
||||
+ dev_info(priv->device, "Found internal PHY node\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return -ENODEV;
|
||||
+}
|
||||
+
|
||||
+static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
|
||||
+{
|
||||
+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (gmac->internal_phy_powered) {
|
||||
+ dev_warn(priv->device, "Internal PHY already powered\n");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ dev_info(priv->device, "Powering internal PHY\n");
|
||||
+ ret = clk_prepare_enable(gmac->ephy_clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->device, "Cannot enable internal PHY\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Make sure the EPHY is properly reseted, as U-Boot may leave
|
||||
+ * it at deasserted state, and thus it may fail to reset EMAC.
|
||||
+ */
|
||||
+ reset_control_assert(gmac->rst_ephy);
|
||||
+
|
||||
+ ret = reset_control_deassert(gmac->rst_ephy);
|
||||
+ if (ret) {
|
||||
+ dev_err(priv->device, "Cannot deassert internal phy\n");
|
||||
+ clk_disable_unprepare(gmac->ephy_clk);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ gmac->internal_phy_powered = true;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
|
||||
+{
|
||||
+ if (!gmac->internal_phy_powered)
|
||||
+ return 0;
|
||||
+
|
||||
+ clk_disable_unprepare(gmac->ephy_clk);
|
||||
+ reset_control_assert(gmac->rst_ephy);
|
||||
+ gmac->internal_phy_powered = false;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* MDIO multiplexing switch function
|
||||
+ * This function is called by the mdio-mux layer when it thinks the mdio bus
|
||||
+ * multiplexer needs to switch.
|
||||
+ * 'current_child' is the current value of the mux register
|
||||
+ * 'desired_child' is the value of the 'reg' property of the target child MDIO
|
||||
+ * node.
|
||||
+ * The first time this function is called, current_child == -1.
|
||||
+ * If current_child == desired_child, then the mux is already set to the
|
||||
+ * correct bus.
|
||||
+ */
|
||||
+static int mdio_mux_syscon_switch_fn(int current_child, int desired_child,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct stmmac_priv *priv = data;
|
||||
+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
|
||||
+ u32 reg, val;
|
||||
+ int ret = 0;
|
||||
+ bool need_power_ephy = false;
|
||||
+
|
||||
+ if (current_child ^ desired_child) {
|
||||
+ regmap_read(gmac->regmap, SYSCON_EMAC_REG, ®);
|
||||
+ switch (desired_child) {
|
||||
+ case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID:
|
||||
+ dev_info(priv->device, "Switch mux to internal PHY");
|
||||
+ val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;
|
||||
+
|
||||
+ need_power_ephy = true;
|
||||
+ break;
|
||||
+ case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID:
|
||||
+ dev_info(priv->device, "Switch mux to external PHY");
|
||||
+ val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN;
|
||||
+ need_power_ephy = false;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(priv->device, "Invalid child ID %x\n",
|
||||
+ desired_child);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ regmap_write(gmac->regmap, SYSCON_EMAC_REG, val);
|
||||
+ if (need_power_ephy) {
|
||||
+ ret = sun8i_dwmac_power_internal_phy(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ } else {
|
||||
+ sun8i_dwmac_unpower_internal_phy(gmac);
|
||||
+ }
|
||||
+ /* After changing syscon value, the MAC need reset or it will
|
||||
+ * use the last value (and so the last PHY set).
|
||||
+ */
|
||||
+ ret = sun8i_dwmac_reset(priv);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct device_node *mdio_mux;
|
||||
+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
|
||||
+
|
||||
+ mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
|
||||
+ if (!mdio_mux)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn,
|
||||
+ &gmac->mux_handle, priv, priv->mii);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
|
||||
{
|
||||
struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
|
||||
@@ -648,35 +807,25 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
|
||||
"Current syscon value is not the default %x (expect %x)\n",
|
||||
val, reg);
|
||||
|
||||
- if (gmac->variant->internal_phy) {
|
||||
- if (!gmac->use_internal_phy) {
|
||||
- /* switch to external PHY interface */
|
||||
- reg &= ~H3_EPHY_SELECT;
|
||||
- } else {
|
||||
- reg |= H3_EPHY_SELECT;
|
||||
- reg &= ~H3_EPHY_SHUTDOWN;
|
||||
- dev_dbg(priv->device, "Select internal_phy %x\n", reg);
|
||||
-
|
||||
- if (of_property_read_bool(priv->plat->phy_node,
|
||||
- "allwinner,leds-active-low"))
|
||||
- reg |= H3_EPHY_LED_POL;
|
||||
- else
|
||||
- reg &= ~H3_EPHY_LED_POL;
|
||||
-
|
||||
- /* Force EPHY xtal frequency to 24MHz. */
|
||||
- reg |= H3_EPHY_CLK_SEL;
|
||||
-
|
||||
- ret = of_mdio_parse_addr(priv->device,
|
||||
- priv->plat->phy_node);
|
||||
- if (ret < 0) {
|
||||
- dev_err(priv->device, "Could not parse MDIO addr\n");
|
||||
- return ret;
|
||||
- }
|
||||
- /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
|
||||
- * address. No need to mask it again.
|
||||
- */
|
||||
- reg |= ret << H3_EPHY_ADDR_SHIFT;
|
||||
+ if (gmac->variant->soc_has_internal_phy) {
|
||||
+ if (of_property_read_bool(priv->plat->phy_node,
|
||||
+ "allwinner,leds-active-low"))
|
||||
+ reg |= H3_EPHY_LED_POL;
|
||||
+ else
|
||||
+ reg &= ~H3_EPHY_LED_POL;
|
||||
+
|
||||
+ /* Force EPHY xtal frequency to 24MHz. */
|
||||
+ reg |= H3_EPHY_CLK_SEL;
|
||||
+
|
||||
+ ret = of_mdio_parse_addr(priv->device, priv->plat->phy_node);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(priv->device, "Could not parse MDIO addr\n");
|
||||
+ return ret;
|
||||
}
|
||||
+ /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
|
||||
+ * address. No need to mask it again.
|
||||
+ */
|
||||
+ reg |= 1 << H3_EPHY_ADDR_SHIFT;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
|
||||
@@ -746,81 +895,21 @@ static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac)
|
||||
regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg);
|
||||
}
|
||||
|
||||
-static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
|
||||
+static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
|
||||
{
|
||||
- struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
|
||||
- int ret;
|
||||
-
|
||||
- if (!gmac->use_internal_phy)
|
||||
- return 0;
|
||||
-
|
||||
- ret = clk_prepare_enable(gmac->ephy_clk);
|
||||
- if (ret) {
|
||||
- dev_err(priv->device, "Cannot enable ephy\n");
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- /* Make sure the EPHY is properly reseted, as U-Boot may leave
|
||||
- * it at deasserted state, and thus it may fail to reset EMAC.
|
||||
- */
|
||||
- reset_control_assert(gmac->rst_ephy);
|
||||
+ struct sunxi_priv_data *gmac = priv;
|
||||
|
||||
- ret = reset_control_deassert(gmac->rst_ephy);
|
||||
- if (ret) {
|
||||
- dev_err(priv->device, "Cannot deassert ephy\n");
|
||||
- clk_disable_unprepare(gmac->ephy_clk);
|
||||
- return ret;
|
||||
+ if (gmac->variant->soc_has_internal_phy) {
|
||||
+ /* sun8i_dwmac_exit could be called with mdiomux uninit */
|
||||
+ if (gmac->mux_handle)
|
||||
+ mdio_mux_uninit(gmac->mux_handle);
|
||||
+ if (gmac->internal_phy_powered)
|
||||
+ sun8i_dwmac_unpower_internal_phy(gmac);
|
||||
}
|
||||
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
|
||||
-{
|
||||
- if (!gmac->use_internal_phy)
|
||||
- return 0;
|
||||
-
|
||||
- clk_disable_unprepare(gmac->ephy_clk);
|
||||
- reset_control_assert(gmac->rst_ephy);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/* sun8i_power_phy() - Activate the PHY:
|
||||
- * In case of error, no need to call sun8i_unpower_phy(),
|
||||
- * it will be called anyway by sun8i_dwmac_exit()
|
||||
- */
|
||||
-static int sun8i_power_phy(struct stmmac_priv *priv)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- ret = sun8i_dwmac_power_internal_phy(priv);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- ret = sun8i_dwmac_set_syscon(priv);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
-
|
||||
- /* After changing syscon value, the MAC need reset or it will use
|
||||
- * the last value (and so the last PHY set.
|
||||
- */
|
||||
- ret = sun8i_dwmac_reset(priv);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void sun8i_unpower_phy(struct sunxi_priv_data *gmac)
|
||||
-{
|
||||
sun8i_dwmac_unset_syscon(gmac);
|
||||
- sun8i_dwmac_unpower_internal_phy(gmac);
|
||||
-}
|
||||
-
|
||||
-static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
|
||||
-{
|
||||
- struct sunxi_priv_data *gmac = priv;
|
||||
|
||||
- sun8i_unpower_phy(gmac);
|
||||
+ reset_control_put(gmac->rst_ephy);
|
||||
|
||||
clk_disable_unprepare(gmac->tx_clk);
|
||||
|
||||
@@ -849,7 +938,7 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
|
||||
if (!mac)
|
||||
return NULL;
|
||||
|
||||
- ret = sun8i_power_phy(priv);
|
||||
+ ret = sun8i_dwmac_set_syscon(priv);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
@@ -889,6 +978,8 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
|
||||
struct sunxi_priv_data *gmac;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
+ struct stmmac_priv *priv;
|
||||
+ struct net_device *ndev;
|
||||
|
||||
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||||
if (ret)
|
||||
@@ -932,29 +1023,6 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
plat_dat->interface = of_get_phy_mode(dev->of_node);
|
||||
- if (plat_dat->interface == gmac->variant->internal_phy) {
|
||||
- dev_info(&pdev->dev, "Will use internal PHY\n");
|
||||
- gmac->use_internal_phy = true;
|
||||
- gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0);
|
||||
- if (IS_ERR(gmac->ephy_clk)) {
|
||||
- ret = PTR_ERR(gmac->ephy_clk);
|
||||
- dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL);
|
||||
- if (IS_ERR(gmac->rst_ephy)) {
|
||||
- ret = PTR_ERR(gmac->rst_ephy);
|
||||
- if (ret == -EPROBE_DEFER)
|
||||
- return ret;
|
||||
- dev_err(&pdev->dev, "No EPHY reset control found %d\n",
|
||||
- ret);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- } else {
|
||||
- dev_info(&pdev->dev, "Will use external PHY\n");
|
||||
- gmac->use_internal_phy = false;
|
||||
- }
|
||||
|
||||
/* platform data specifying hardware features and callbacks.
|
||||
* hardware features were copied from Allwinner drivers.
|
||||
@@ -973,9 +1041,34 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
|
||||
|
||||
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||||
if (ret)
|
||||
- sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
|
||||
+ goto dwmac_exit;
|
||||
+
|
||||
+ ndev = dev_get_drvdata(&pdev->dev);
|
||||
+ priv = netdev_priv(ndev);
|
||||
+ /* The mux must be registered after parent MDIO
|
||||
+ * so after stmmac_dvr_probe()
|
||||
+ */
|
||||
+ if (gmac->variant->soc_has_internal_phy) {
|
||||
+ ret = get_ephy_nodes(priv);
|
||||
+ if (ret)
|
||||
+ goto dwmac_exit;
|
||||
+ ret = sun8i_dwmac_register_mdio_mux(priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Failed to register mux\n");
|
||||
+ goto dwmac_mux;
|
||||
+ }
|
||||
+ } else {
|
||||
+ ret = sun8i_dwmac_reset(priv);
|
||||
+ if (ret)
|
||||
+ goto dwmac_exit;
|
||||
+ }
|
||||
|
||||
return ret;
|
||||
+dwmac_mux:
|
||||
+ sun8i_dwmac_unset_syscon(gmac);
|
||||
+dwmac_exit:
|
||||
+ sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
|
||||
+return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun8i_dwmac_match[] = {
|
@ -0,0 +1,37 @@
|
||||
From a8ff8ccb45d37efa64476958fc5e9a8d9716b23b Mon Sep 17 00:00:00 2001
|
||||
From: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Date: Tue, 24 Oct 2017 19:57:14 +0200
|
||||
Subject: [PATCH] net: stmmac: sun8i: Restore the compatibles
|
||||
|
||||
The original dwmac-sun8i DT bindings have some issue on how to handle
|
||||
integrated PHY and was reverted in last RC of 4.13.
|
||||
But now we have a solution so we need to get back that was reverted.
|
||||
|
||||
This patch restore compatibles about dwmac-sun8i
|
||||
This reverts commit ad4540cc5aa3 ("net: stmmac: sun8i: Remove the compatibles")
|
||||
|
||||
Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
index b3eb344bb158d..e5ff734d4f9b2 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
@@ -1072,6 +1072,14 @@ return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun8i_dwmac_match[] = {
|
||||
+ { .compatible = "allwinner,sun8i-h3-emac",
|
||||
+ .data = &emac_variant_h3 },
|
||||
+ { .compatible = "allwinner,sun8i-v3s-emac",
|
||||
+ .data = &emac_variant_v3s },
|
||||
+ { .compatible = "allwinner,sun8i-a83t-emac",
|
||||
+ .data = &emac_variant_a83t },
|
||||
+ { .compatible = "allwinner,sun50i-a64-emac",
|
||||
+ .data = &emac_variant_a64 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);
|
@ -0,0 +1,106 @@
|
||||
From 4497478c60c04d2bf37082e27fc98f4f835db96b Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Date: Tue, 14 Nov 2017 11:15:54 +0100
|
||||
Subject: [PATCH] net: stmmac: fix LPI transitioning for dwmac4
|
||||
|
||||
The LPI transitioning logic in stmmac_main uses
|
||||
priv->tx_path_in_lpi_mode to enter/exit LPI.
|
||||
|
||||
However, priv->tx_path_in_lpi_mode is assigned
|
||||
using the return value from host_irq_status().
|
||||
|
||||
So for dwmac4, priv->tx_path_in_lpi_mode was always false,
|
||||
so stmmac_tx_clean() would always try to put us in eee mode,
|
||||
and stmmac_xmit() would never take us out of eee mode.
|
||||
|
||||
To fix this, make host_irq_status() read and return the LPI
|
||||
irq status also for dwmac4.
|
||||
|
||||
This also increments the existing LPI counters, so that
|
||||
ethtool --statistics shows LPI transitions also for dwmac4.
|
||||
|
||||
For dwmac1000, irqs are enabled/disabled using the register
|
||||
named "Interrupt Mask Register", and thus setting a bit disables
|
||||
that specific irq.
|
||||
|
||||
For dwmac4 the matching register is named "MAC_Interrupt_Enable",
|
||||
and thus setting a bit enables that specific irq.
|
||||
|
||||
Looking at dwmac1000_core.c, the irqs that are always enabled are:
|
||||
LPI and PMT.
|
||||
|
||||
Looking at dwmac4_core.c, the irqs that are always enabled are:
|
||||
PMT.
|
||||
|
||||
To be able to read the LPI irq status, we need to enable the LPI
|
||||
irq also for dwmac4.
|
||||
|
||||
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 7 ++++++-
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 19 +++++++++++++++++++
|
||||
2 files changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
index aeda3ab2d761c..789dad8a07b5c 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
@@ -98,7 +98,7 @@
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
|
||||
GMAC_INT_PCS_ANE)
|
||||
|
||||
-#define GMAC_INT_DEFAULT_MASK GMAC_INT_PMT_EN
|
||||
+#define GMAC_INT_DEFAULT_MASK (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
|
||||
|
||||
enum dwmac4_irq_status {
|
||||
time_stamp_irq = 0x00001000,
|
||||
@@ -106,6 +106,7 @@ enum dwmac4_irq_status {
|
||||
mmc_tx_irq = 0x00000400,
|
||||
mmc_rx_irq = 0x00000200,
|
||||
mmc_irq = 0x00000100,
|
||||
+ lpi_irq = 0x00000020,
|
||||
pmt_irq = 0x00000010,
|
||||
};
|
||||
|
||||
@@ -132,6 +133,10 @@ enum power_event {
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPITXA BIT(19) /* Enable LPI TX Automate */
|
||||
#define GMAC4_LPI_CTRL_STATUS_PLS BIT(17) /* PHY Link Status */
|
||||
#define GMAC4_LPI_CTRL_STATUS_LPIEN BIT(16) /* LPI Enable */
|
||||
+#define GMAC4_LPI_CTRL_STATUS_RLPIEX BIT(3) /* Receive LPI Exit */
|
||||
+#define GMAC4_LPI_CTRL_STATUS_RLPIEN BIT(2) /* Receive LPI Entry */
|
||||
+#define GMAC4_LPI_CTRL_STATUS_TLPIEX BIT(1) /* Transmit LPI Exit */
|
||||
+#define GMAC4_LPI_CTRL_STATUS_TLPIEN BIT(0) /* Transmit LPI Entry */
|
||||
|
||||
/* MAC Debug bitmap */
|
||||
#define GMAC_DEBUG_TFCSTS_MASK GENMASK(18, 17)
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
index 2f7d7ec59962a..f3ed8f7853eb4 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
@@ -580,6 +580,25 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
|
||||
+ /* MAC tx/rx EEE LPI entry/exit interrupts */
|
||||
+ if (intr_status & lpi_irq) {
|
||||
+ /* Clear LPI interrupt by reading MAC_LPI_Control_Status */
|
||||
+ u32 status = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
|
||||
+
|
||||
+ if (status & GMAC4_LPI_CTRL_STATUS_TLPIEN) {
|
||||
+ ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE;
|
||||
+ x->irq_tx_path_in_lpi_mode_n++;
|
||||
+ }
|
||||
+ if (status & GMAC4_LPI_CTRL_STATUS_TLPIEX) {
|
||||
+ ret |= CORE_IRQ_TX_PATH_EXIT_LPI_MODE;
|
||||
+ x->irq_tx_path_exit_lpi_mode_n++;
|
||||
+ }
|
||||
+ if (status & GMAC4_LPI_CTRL_STATUS_RLPIEN)
|
||||
+ x->irq_rx_path_in_lpi_mode_n++;
|
||||
+ if (status & GMAC4_LPI_CTRL_STATUS_RLPIEX)
|
||||
+ x->irq_rx_path_exit_lpi_mode_n++;
|
||||
+ }
|
||||
+
|
||||
dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
|
||||
if (intr_status & PCS_RGSMIIIS_IRQ)
|
||||
dwmac4_phystatus(ioaddr, x);
|
@ -0,0 +1,32 @@
|
||||
From 1c08ac0c4bd8e9d66c4dde29bc496c3b430dd028 Mon Sep 17 00:00:00 2001
|
||||
From: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Date: Tue, 28 Nov 2017 17:48:22 +0100
|
||||
Subject: [PATCH] net: stmmac: dwmac-sun8i: fix allwinner,leds-active-low
|
||||
handling
|
||||
|
||||
The driver expect "allwinner,leds-active-low" to be in PHY node, but
|
||||
the binding doc expect it to be in MAC node.
|
||||
|
||||
Since all board DT use it also in MAC node, the driver need to search
|
||||
allwinner,leds-active-low in MAC node.
|
||||
|
||||
Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
index e5ff734d4f9b2..9eb7f65d8000d 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
@@ -808,8 +808,7 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
|
||||
val, reg);
|
||||
|
||||
if (gmac->variant->soc_has_internal_phy) {
|
||||
- if (of_property_read_bool(priv->plat->phy_node,
|
||||
- "allwinner,leds-active-low"))
|
||||
+ if (of_property_read_bool(node, "allwinner,leds-active-low"))
|
||||
reg |= H3_EPHY_LED_POL;
|
||||
else
|
||||
reg &= ~H3_EPHY_LED_POL;
|
@ -0,0 +1,30 @@
|
||||
From f6454f80e8a965fca203dab28723f68ec78db608 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Gaignard <benjamin.gaignard@linaro.org>
|
||||
Date: Wed, 29 Nov 2017 15:20:00 +0100
|
||||
Subject: [PATCH] ethernet: dwmac-stm32: Fix copyright
|
||||
|
||||
Uniformize STMicroelectronics copyrights header
|
||||
|
||||
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
|
||||
CC: Alexandre Torgue <alexandre.torgue@st.com>
|
||||
Acked-by: Alexandre TORGUE <alexandre.torgue@st.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
|
||||
index 61cb24810d101..9e6db16af663b 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU
|
||||
*
|
||||
- * Copyright (C) Alexandre Torgue 2015
|
||||
- * Author: Alexandre Torgue <alexandre.torgue@gmail.com>
|
||||
+ * Copyright (C) STMicroelectronics SA 2017
|
||||
+ * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
|
||||
* License terms: GNU General Public License (GPL), version 2
|
||||
*
|
||||
*/
|
@ -0,0 +1,128 @@
|
||||
From 5a6a0445d1edb28fc89fd12b49cda2d5114e2665 Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Date: Thu, 7 Dec 2017 23:56:10 +0100
|
||||
Subject: [PATCH] net: stmmac: fix broken dma_interrupt handling for
|
||||
multi-queues
|
||||
|
||||
There is nothing that says that number of TX queues == number of RX
|
||||
queues. E.g. the ARTPEC-6 SoC has 2 TX queues and 1 RX queue.
|
||||
|
||||
This code is obviously wrong:
|
||||
for (chan = 0; chan < tx_channel_count; chan++) {
|
||||
struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan];
|
||||
|
||||
priv->rx_queue has size MTL_MAX_RX_QUEUES, so this will send an
|
||||
uninitialized napi_struct to __napi_schedule(), causing us to
|
||||
crash in net_rx_action(), because napi_struct->poll is zero.
|
||||
|
||||
[12846.759880] Unable to handle kernel NULL pointer dereference at virtual address 00000000
|
||||
[12846.768014] pgd = (ptrval)
|
||||
[12846.770742] [00000000] *pgd=39ec7831, *pte=00000000, *ppte=00000000
|
||||
[12846.777023] Internal error: Oops: 80000007 [#1] PREEMPT SMP ARM
|
||||
[12846.782942] Modules linked in:
|
||||
[12846.785998] CPU: 0 PID: 161 Comm: dropbear Not tainted 4.15.0-rc2-00285-gf5fb5f2f39a7 #36
|
||||
[12846.794177] Hardware name: Axis ARTPEC-6 Platform
|
||||
[12846.798879] task: (ptrval) task.stack: (ptrval)
|
||||
[12846.803407] PC is at 0x0
|
||||
[12846.805942] LR is at net_rx_action+0x274/0x43c
|
||||
[12846.810383] pc : [<00000000>] lr : [<80bff064>] psr: 200e0113
|
||||
[12846.816648] sp : b90d9ae8 ip : b90d9ae8 fp : b90d9b44
|
||||
[12846.821871] r10: 00000008 r9 : 0013250e r8 : 00000100
|
||||
[12846.827094] r7 : 0000012c r6 : 00000000 r5 : 00000001 r4 : bac84900
|
||||
[12846.833619] r3 : 00000000 r2 : b90d9b08 r1 : 00000000 r0 : bac84900
|
||||
|
||||
Since each DMA channel can be used for rx and tx simultaneously,
|
||||
the current code should probably be rewritten so that napi_struct is
|
||||
embedded in a new struct stmmac_channel.
|
||||
That way, stmmac_poll() can call stmmac_tx_clean() on just the tx queue
|
||||
where we got the IRQ, instead of looping through all tx queues.
|
||||
This is also how the xgbe driver does it (another driver for this IP).
|
||||
|
||||
Fixes: c22a3f48ef99 ("net: stmmac: adding multiple napi mechanism")
|
||||
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 54 +++++++++++++++++++----
|
||||
1 file changed, 46 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
index d7250539d0bd0..c52a9963c19d5 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
@@ -1997,22 +1997,60 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
|
||||
static void stmmac_dma_interrupt(struct stmmac_priv *priv)
|
||||
{
|
||||
u32 tx_channel_count = priv->plat->tx_queues_to_use;
|
||||
- int status;
|
||||
+ u32 rx_channel_count = priv->plat->rx_queues_to_use;
|
||||
+ u32 channels_to_check = tx_channel_count > rx_channel_count ?
|
||||
+ tx_channel_count : rx_channel_count;
|
||||
u32 chan;
|
||||
+ bool poll_scheduled = false;
|
||||
+ int status[channels_to_check];
|
||||
+
|
||||
+ /* Each DMA channel can be used for rx and tx simultaneously, yet
|
||||
+ * napi_struct is embedded in struct stmmac_rx_queue rather than in a
|
||||
+ * stmmac_channel struct.
|
||||
+ * Because of this, stmmac_poll currently checks (and possibly wakes)
|
||||
+ * all tx queues rather than just a single tx queue.
|
||||
+ */
|
||||
+ for (chan = 0; chan < channels_to_check; chan++)
|
||||
+ status[chan] = priv->hw->dma->dma_interrupt(priv->ioaddr,
|
||||
+ &priv->xstats,
|
||||
+ chan);
|
||||
|
||||
- for (chan = 0; chan < tx_channel_count; chan++) {
|
||||
- struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan];
|
||||
+ for (chan = 0; chan < rx_channel_count; chan++) {
|
||||
+ if (likely(status[chan] & handle_rx)) {
|
||||
+ struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan];
|
||||
|
||||
- status = priv->hw->dma->dma_interrupt(priv->ioaddr,
|
||||
- &priv->xstats, chan);
|
||||
- if (likely((status & handle_rx)) || (status & handle_tx)) {
|
||||
if (likely(napi_schedule_prep(&rx_q->napi))) {
|
||||
stmmac_disable_dma_irq(priv, chan);
|
||||
__napi_schedule(&rx_q->napi);
|
||||
+ poll_scheduled = true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If we scheduled poll, we already know that tx queues will be checked.
|
||||
+ * If we didn't schedule poll, see if any DMA channel (used by tx) has a
|
||||
+ * completed transmission, if so, call stmmac_poll (once).
|
||||
+ */
|
||||
+ if (!poll_scheduled) {
|
||||
+ for (chan = 0; chan < tx_channel_count; chan++) {
|
||||
+ if (status[chan] & handle_tx) {
|
||||
+ /* It doesn't matter what rx queue we choose
|
||||
+ * here. We use 0 since it always exists.
|
||||
+ */
|
||||
+ struct stmmac_rx_queue *rx_q =
|
||||
+ &priv->rx_queue[0];
|
||||
+
|
||||
+ if (likely(napi_schedule_prep(&rx_q->napi))) {
|
||||
+ stmmac_disable_dma_irq(priv, chan);
|
||||
+ __napi_schedule(&rx_q->napi);
|
||||
+ }
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
+ }
|
||||
|
||||
- if (unlikely(status & tx_hard_error_bump_tc)) {
|
||||
+ for (chan = 0; chan < tx_channel_count; chan++) {
|
||||
+ if (unlikely(status[chan] & tx_hard_error_bump_tc)) {
|
||||
/* Try to bump up the dma threshold on this failure */
|
||||
if (unlikely(priv->xstats.threshold != SF_DMA_MODE) &&
|
||||
(tc <= 256)) {
|
||||
@@ -2029,7 +2067,7 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
|
||||
chan);
|
||||
priv->xstats.threshold = tc;
|
||||
}
|
||||
- } else if (unlikely(status == tx_hard_error)) {
|
||||
+ } else if (unlikely(status[chan] == tx_hard_error)) {
|
||||
stmmac_tx_err(priv, chan);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
From bdb421663d936eb9b29c743a668614276cf3b97d Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Date: Fri, 29 Dec 2017 19:56:32 -0800
|
||||
Subject: [PATCH] net: stmmac: Pad ring number with zeroes in display_ring()
|
||||
|
||||
Make the printing of the ring number consistent and properly aligned by
|
||||
padding the ring number with up to 3 zeroes, which covers the maximum
|
||||
ring size. This makes it a lot easier to see outliers in debug prints.
|
||||
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 2 +-
|
||||
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 2 +-
|
||||
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 2 +-
|
||||
3 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
|
||||
index 7e089bf906b4f..2fd8456999f69 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
|
||||
@@ -406,7 +406,7 @@ static void dwmac4_display_ring(void *head, unsigned int size, bool rx)
|
||||
pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
- pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
+ pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, (unsigned int)virt_to_phys(p),
|
||||
le32_to_cpu(p->des0), le32_to_cpu(p->des1),
|
||||
le32_to_cpu(p->des2), le32_to_cpu(p->des3));
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
|
||||
index 2a828a3128142..b47cb5c4da513 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
|
||||
@@ -428,7 +428,7 @@ static void enh_desc_display_ring(void *head, unsigned int size, bool rx)
|
||||
u64 x;
|
||||
|
||||
x = *(u64 *)ep;
|
||||
- pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
+ pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
|
||||
i, (unsigned int)virt_to_phys(ep),
|
||||
(unsigned int)x, (unsigned int)(x >> 32),
|
||||
ep->basic.des2, ep->basic.des3);
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
|
||||
index db4cee57bb246..ebd9e5e00f161 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
|
||||
@@ -288,7 +288,7 @@ static void ndesc_display_ring(void *head, unsigned int size, bool rx)
|
||||
u64 x;
|
||||
|
||||
x = *(u64 *)p;
|
||||
- pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x",
|
||||
+ pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x",
|
||||
i, (unsigned int)virt_to_phys(p),
|
||||
(unsigned int)x, (unsigned int)(x >> 32),
|
||||
p->des2, p->des3);
|
@ -0,0 +1,133 @@
|
||||
From 37512b42f082d784a012c3734ef109f25d199786 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Mon, 15 Jan 2018 18:10:12 +0100
|
||||
Subject: [PATCH] net: stmmac: dwmac-meson8b: only configure the clocks in
|
||||
RGMII mode
|
||||
|
||||
Neither the m25_div_clk nor the m250_div_clk or m250_mux_clk are used in
|
||||
RMII mode. The m25_div_clk output is routed to the RGMII PHY's "RGMII
|
||||
clock".
|
||||
This means that we don't need to configure the clocks in RMII mode. The
|
||||
driver however did this - with no effect since the clocks are not routed
|
||||
to the PHY in RMII mode.
|
||||
|
||||
While here also rename meson8b_init_clk to meson8b_init_rgmii_tx_clk to
|
||||
make it easier to understand the code.
|
||||
|
||||
Fixes: 566e8251625304 ("net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC")
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Tested-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
.../net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 46 ++++++++++------------
|
||||
1 file changed, 21 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
||||
index 4404650b32c5e..c6f87e9c4ccb3 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
||||
@@ -81,7 +81,7 @@ static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg,
|
||||
writel(data, dwmac->regs + reg);
|
||||
}
|
||||
|
||||
-static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
|
||||
+static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
int i, ret;
|
||||
@@ -176,7 +176,6 @@ static int meson8b_init_clk(struct meson8b_dwmac *dwmac)
|
||||
static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
||||
{
|
||||
int ret;
|
||||
- unsigned long clk_rate;
|
||||
u8 tx_dly_val = 0;
|
||||
|
||||
switch (dwmac->phy_mode) {
|
||||
@@ -191,9 +190,6 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
||||
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
- /* Generate a 25MHz clock for the PHY */
|
||||
- clk_rate = 25 * 1000 * 1000;
|
||||
-
|
||||
/* enable RGMII mode */
|
||||
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
|
||||
PRG_ETH0_RGMII_MODE);
|
||||
@@ -204,12 +200,24 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
||||
|
||||
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
|
||||
tx_dly_val << PRG_ETH0_TXDLY_SHIFT);
|
||||
+
|
||||
+ ret = clk_prepare_enable(dwmac->m25_div_clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Generate the 25MHz RGMII clock for the PHY */
|
||||
+ ret = clk_set_rate(dwmac->m25_div_clk, 25 * 1000 * 1000);
|
||||
+ if (ret) {
|
||||
+ clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
+
|
||||
+ dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_RMII:
|
||||
- /* Use the rate of the mux clock for the internal RMII PHY */
|
||||
- clk_rate = clk_get_rate(dwmac->m250_mux_clk);
|
||||
-
|
||||
/* disable RGMII mode -> enables RMII mode */
|
||||
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE,
|
||||
0);
|
||||
@@ -231,20 +239,6 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- ret = clk_prepare_enable(dwmac->m25_div_clk);
|
||||
- if (ret) {
|
||||
- dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n");
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
- ret = clk_set_rate(dwmac->m25_div_clk, clk_rate);
|
||||
- if (ret) {
|
||||
- clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
-
|
||||
- dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n");
|
||||
- return ret;
|
||||
- }
|
||||
-
|
||||
/* enable TX_CLK and PHY_REF_CLK generator */
|
||||
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK,
|
||||
PRG_ETH0_TX_AND_PHY_REF_CLK);
|
||||
@@ -294,7 +288,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
||||
&dwmac->tx_delay_ns))
|
||||
dwmac->tx_delay_ns = 2;
|
||||
|
||||
- ret = meson8b_init_clk(dwmac);
|
||||
+ ret = meson8b_init_rgmii_tx_clk(dwmac);
|
||||
if (ret)
|
||||
goto err_remove_config_dt;
|
||||
|
||||
@@ -311,7 +305,8 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_clk_disable:
|
||||
- clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
+ if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
|
||||
+ clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
err_remove_config_dt:
|
||||
stmmac_remove_config_dt(pdev, plat_dat);
|
||||
|
||||
@@ -322,7 +317,8 @@ static int meson8b_dwmac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
|
||||
|
||||
- clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
+ if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
|
||||
+ clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
|
||||
return stmmac_pltfr_remove(pdev);
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
From 4f6a71b84e1afdf13827741e7421a844203cf8d0 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Mon, 15 Jan 2018 18:10:13 +0100
|
||||
Subject: [PATCH] net: stmmac: dwmac-meson8b: fix internal RGMII clock
|
||||
configuration
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Tests (using an oscilloscope and an Odroid-C1 board with a RTL8211F
|
||||
RGMII PHY) have shown that the PRG_ETH0 register behaves as follows:
|
||||
- bit 4 is a mux to choose between two parent clocks. according to the
|
||||
public S805 datasheet the only supported parent clock is MPLL2 (this
|
||||
was not verified using the oscilloscope).
|
||||
The public S805/S905 datasheet claims that this bit is reserved.
|
||||
- bits 9:7 control a one-based divider (register value 1 means "divide
|
||||
by 1", etc.) for the input clock. we call this clock the "m250_div"
|
||||
clock because it's value is always supposed to be (close to) 250MHz
|
||||
(see below for an explanation).
|
||||
The description in the public S805/S905 datasheet is a bit cryptic,
|
||||
but it comes down to "input clock = 250MHz * value" (which could also
|
||||
be expressed as "250MHz = input clock / value")
|
||||
- there seems to be an internal fixed divide-by-2 clock which takes the
|
||||
output from the m250_div and divides it by 2. This is not unusual on
|
||||
Amlogic SoCs, since the SDIO (MMC) driver also uses an internal fixed
|
||||
divide-by-2 clock.
|
||||
This is not documented in the public S805/S905 datasheet
|
||||
- bit 10 controls a gate clock which enables or disables the RGMII TX
|
||||
clock (which is an output on the MAC/SoC and an input in the PHY). we
|
||||
call this the "rgmii_tx_en" clock. if this bit is set to "0" the RGMII
|
||||
TX clock output is close to 0
|
||||
The description for this bit in the public S805/S905 datasheet is
|
||||
"Generate 25MHz clock for PHY". Based on these tests it's believed
|
||||
that this is wrong, and should probably read "Generate the 125MHz
|
||||
RGMII TX clock for the PHY"
|
||||
- the RGMII TX clock has to be set to 125MHz - the IP block adjusts the
|
||||
output (automatically) depending on the line speed (RGMII specifies
|
||||
that Gbit connections use a 125MHz clock, 100Mbit/s connections use a
|
||||
25MHz clock and 10Mbit/s connections use a 2.5MHz clock. only Gbit and
|
||||
100Mbit/s were tested with an oscilloscope). Due to the requirement
|
||||
that this clock always has to be set to 125MHz and due to the fixed
|
||||
divide-by-2 parent clock this means that m250_div will always end up
|
||||
with a rate of (close to) 250MHz.
|
||||
- bits 6:5 are the TX delay, which is also named "clock phase" in some
|
||||
of Amlogic's older GPL kernel sources.
|
||||
|
||||
The PHY also has an XTAL_IN pin where a 25MHz clock has to be provided.
|
||||
Tests with the oscilloscope have shown that this is routed to a crystal
|
||||
right next to the RTL8211F PHY. The same seems to be true on the Khadas
|
||||
VIM2 (which uses a GXM SoC) board - however the 25MHz crystal is on the
|
||||
other side of the PCB there.
|
||||
|
||||
This updates the clocks in the dwmac-meson8b driver by replacing the
|
||||
"m25_div" with the "rgmii_tx_en" clock and additionally introducing a
|
||||
fixed divide-by-2 clock between "m250_div" and "rgmii_tx_en".
|
||||
Now we also need to set a frequency of 125MHz on the RGMII clock
|
||||
(opposed to the 25MHz we set before, with that non-existing
|
||||
divide-by-5-or-10 divider).
|
||||
|
||||
Special thanks go to Linus Lüssing for testing the various bits and
|
||||
checking the results with an oscilloscope on his Odroid-C1!
|
||||
|
||||
Fixes: 566e8251625304 ("net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC")
|
||||
Reported-by: Emiliano Ingrassia <ingrassia@epigenesys.com>
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Acked-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Tested-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
.../net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 79 +++++++++++++---------
|
||||
1 file changed, 47 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
||||
index c6f87e9c4ccb3..7930a152dd634 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
||||
@@ -40,9 +40,7 @@
|
||||
#define PRG_ETH0_CLK_M250_DIV_SHIFT 7
|
||||
#define PRG_ETH0_CLK_M250_DIV_WIDTH 3
|
||||
|
||||
-/* divides the result of m25_sel by either 5 (bit unset) or 10 (bit set) */
|
||||
-#define PRG_ETH0_CLK_M25_DIV_SHIFT 10
|
||||
-#define PRG_ETH0_CLK_M25_DIV_WIDTH 1
|
||||
+#define PRG_ETH0_RGMII_TX_CLK_EN 10
|
||||
|
||||
#define PRG_ETH0_INVERTED_RMII_CLK BIT(11)
|
||||
#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12)
|
||||
@@ -63,8 +61,11 @@ struct meson8b_dwmac {
|
||||
struct clk_divider m250_div;
|
||||
struct clk *m250_div_clk;
|
||||
|
||||
- struct clk_divider m25_div;
|
||||
- struct clk *m25_div_clk;
|
||||
+ struct clk_fixed_factor fixed_div2;
|
||||
+ struct clk *fixed_div2_clk;
|
||||
+
|
||||
+ struct clk_gate rgmii_tx_en;
|
||||
+ struct clk *rgmii_tx_en_clk;
|
||||
|
||||
u32 tx_delay_ns;
|
||||
};
|
||||
@@ -89,11 +90,6 @@ static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
|
||||
char clk_name[32];
|
||||
const char *clk_div_parents[1];
|
||||
const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
|
||||
- static const struct clk_div_table clk_25m_div_table[] = {
|
||||
- { .val = 0, .div = 5 },
|
||||
- { .val = 1, .div = 10 },
|
||||
- { /* sentinel */ },
|
||||
- };
|
||||
|
||||
/* get the mux parents from DT */
|
||||
for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
|
||||
@@ -150,25 +146,40 @@ static int meson8b_init_rgmii_tx_clk(struct meson8b_dwmac *dwmac)
|
||||
if (WARN_ON(IS_ERR(dwmac->m250_div_clk)))
|
||||
return PTR_ERR(dwmac->m250_div_clk);
|
||||
|
||||
- /* create the m25_div */
|
||||
- snprintf(clk_name, sizeof(clk_name), "%s#m25_div", dev_name(dev));
|
||||
+ /* create the fixed_div2 */
|
||||
+ snprintf(clk_name, sizeof(clk_name), "%s#fixed_div2", dev_name(dev));
|
||||
init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL);
|
||||
- init.ops = &clk_divider_ops;
|
||||
- init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
|
||||
+ init.ops = &clk_fixed_factor_ops;
|
||||
+ init.flags = CLK_SET_RATE_PARENT;
|
||||
clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk);
|
||||
init.parent_names = clk_div_parents;
|
||||
init.num_parents = ARRAY_SIZE(clk_div_parents);
|
||||
|
||||
- dwmac->m25_div.reg = dwmac->regs + PRG_ETH0;
|
||||
- dwmac->m25_div.shift = PRG_ETH0_CLK_M25_DIV_SHIFT;
|
||||
- dwmac->m25_div.width = PRG_ETH0_CLK_M25_DIV_WIDTH;
|
||||
- dwmac->m25_div.table = clk_25m_div_table;
|
||||
- dwmac->m25_div.hw.init = &init;
|
||||
- dwmac->m25_div.flags = CLK_DIVIDER_ALLOW_ZERO;
|
||||
+ dwmac->fixed_div2.mult = 1;
|
||||
+ dwmac->fixed_div2.div = 2;
|
||||
+ dwmac->fixed_div2.hw.init = &init;
|
||||
|
||||
- dwmac->m25_div_clk = devm_clk_register(dev, &dwmac->m25_div.hw);
|
||||
- if (WARN_ON(IS_ERR(dwmac->m25_div_clk)))
|
||||
- return PTR_ERR(dwmac->m25_div_clk);
|
||||
+ dwmac->fixed_div2_clk = devm_clk_register(dev, &dwmac->fixed_div2.hw);
|
||||
+ if (WARN_ON(IS_ERR(dwmac->fixed_div2_clk)))
|
||||
+ return PTR_ERR(dwmac->fixed_div2_clk);
|
||||
+
|
||||
+ /* create the rgmii_tx_en */
|
||||
+ init.name = devm_kasprintf(dev, GFP_KERNEL, "%s#rgmii_tx_en",
|
||||
+ dev_name(dev));
|
||||
+ init.ops = &clk_gate_ops;
|
||||
+ init.flags = CLK_SET_RATE_PARENT;
|
||||
+ clk_div_parents[0] = __clk_get_name(dwmac->fixed_div2_clk);
|
||||
+ init.parent_names = clk_div_parents;
|
||||
+ init.num_parents = ARRAY_SIZE(clk_div_parents);
|
||||
+
|
||||
+ dwmac->rgmii_tx_en.reg = dwmac->regs + PRG_ETH0;
|
||||
+ dwmac->rgmii_tx_en.bit_idx = PRG_ETH0_RGMII_TX_CLK_EN;
|
||||
+ dwmac->rgmii_tx_en.hw.init = &init;
|
||||
+
|
||||
+ dwmac->rgmii_tx_en_clk = devm_clk_register(dev,
|
||||
+ &dwmac->rgmii_tx_en.hw);
|
||||
+ if (WARN_ON(IS_ERR(dwmac->rgmii_tx_en_clk)))
|
||||
+ return PTR_ERR(dwmac->rgmii_tx_en_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -201,18 +212,22 @@ static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
|
||||
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK,
|
||||
tx_dly_val << PRG_ETH0_TXDLY_SHIFT);
|
||||
|
||||
- ret = clk_prepare_enable(dwmac->m25_div_clk);
|
||||
+ /* Configure the 125MHz RGMII TX clock, the IP block changes
|
||||
+ * the output automatically (= without us having to configure
|
||||
+ * a register) based on the line-speed (125MHz for Gbit speeds,
|
||||
+ * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/s).
|
||||
+ */
|
||||
+ ret = clk_set_rate(dwmac->rgmii_tx_en_clk, 125 * 1000 * 1000);
|
||||
if (ret) {
|
||||
- dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n");
|
||||
+ dev_err(&dwmac->pdev->dev,
|
||||
+ "failed to set RGMII TX clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
- /* Generate the 25MHz RGMII clock for the PHY */
|
||||
- ret = clk_set_rate(dwmac->m25_div_clk, 25 * 1000 * 1000);
|
||||
+ ret = clk_prepare_enable(dwmac->rgmii_tx_en_clk);
|
||||
if (ret) {
|
||||
- clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
-
|
||||
- dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n");
|
||||
+ dev_err(&dwmac->pdev->dev,
|
||||
+ "failed to enable the RGMII TX clock\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
@@ -306,7 +321,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
||||
|
||||
err_clk_disable:
|
||||
if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
|
||||
- clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
+ clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
|
||||
err_remove_config_dt:
|
||||
stmmac_remove_config_dt(pdev, plat_dat);
|
||||
|
||||
@@ -318,7 +333,7 @@ static int meson8b_dwmac_remove(struct platform_device *pdev)
|
||||
struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev);
|
||||
|
||||
if (phy_interface_mode_is_rgmii(dwmac->phy_mode))
|
||||
- clk_disable_unprepare(dwmac->m25_div_clk);
|
||||
+ clk_disable_unprepare(dwmac->rgmii_tx_en_clk);
|
||||
|
||||
return stmmac_pltfr_remove(pdev);
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
From 8cad443eacf661796a740903a75cb8944c675b4e Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Date: Thu, 18 Jan 2018 15:12:21 -0800
|
||||
Subject: [PATCH] net: stmmac: Fix reception of Broadcom switches tags
|
||||
|
||||
Broadcom tags inserted by Broadcom switches put a 4 byte header after
|
||||
the MAC SA and before the EtherType, which may look like some sort of 0
|
||||
length LLC/SNAP packet (tcpdump and wireshark do think that way). With
|
||||
ACS enabled in stmmac the packets were truncated to 8 bytes on
|
||||
reception, whereas clearing this bit allowed normal reception to occur.
|
||||
|
||||
In order to make that possible, we need to pass a net_device argument to
|
||||
the different core_init() functions and we are dependent on the Broadcom
|
||||
tagger padding packets correctly (which it now does). To be as little
|
||||
invasive as possible, this is only done for gmac1000 when the network
|
||||
device is DSA-enabled (netdev_uses_dsa() returns true).
|
||||
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/common.h | 2 +-
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 3 ++-
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 12 +++++++++++-
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c | 15 +++++++++++++--
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 12 +++++++++++-
|
||||
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +-
|
||||
6 files changed, 39 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
index ce2ea2d491aca..2ffe76c0ff742 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
|
||||
@@ -474,7 +474,7 @@ struct mac_device_info;
|
||||
/* Helpers to program the MAC core */
|
||||
struct stmmac_ops {
|
||||
/* MAC core initialization */
|
||||
- void (*core_init)(struct mac_device_info *hw, int mtu);
|
||||
+ void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
|
||||
/* Enable the MAC RX/TX */
|
||||
void (*set_mac)(void __iomem *ioaddr, bool enable);
|
||||
/* Enable and verify that the IPC module is supported */
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
index 9eb7f65d8000d..a3fa65b1ca8e5 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
|
||||
@@ -483,7 +483,8 @@ static int sun8i_dwmac_init(struct platform_device *pdev, void *priv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void sun8i_dwmac_core_init(struct mac_device_info *hw, int mtu)
|
||||
+static void sun8i_dwmac_core_init(struct mac_device_info *hw,
|
||||
+ struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 v;
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
|
||||
index 8a86340ff2d34..540d21786a43b 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
|
||||
@@ -25,18 +25,28 @@
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
+#include <net/dsa.h>
|
||||
#include <asm/io.h>
|
||||
#include "stmmac_pcs.h"
|
||||
#include "dwmac1000.h"
|
||||
|
||||
-static void dwmac1000_core_init(struct mac_device_info *hw, int mtu)
|
||||
+static void dwmac1000_core_init(struct mac_device_info *hw,
|
||||
+ struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
+ int mtu = dev->mtu;
|
||||
|
||||
/* Configure GMAC core */
|
||||
value |= GMAC_CORE_INIT;
|
||||
|
||||
+ /* Clear ACS bit because Ethernet switch tagging formats such as
|
||||
+ * Broadcom tags can look like invalid LLC/SNAP packets and cause the
|
||||
+ * hardware to truncate packets on reception.
|
||||
+ */
|
||||
+ if (netdev_uses_dsa(dev))
|
||||
+ value &= ~GMAC_CONTROL_ACS;
|
||||
+
|
||||
if (mtu > 1500)
|
||||
value |= GMAC_CONTROL_2K;
|
||||
if (mtu > 2000)
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
|
||||
index 8ef5173563134..91b23f9db31ad 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
|
||||
@@ -25,15 +25,26 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
+#include <net/dsa.h>
|
||||
#include <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
|
||||
-static void dwmac100_core_init(struct mac_device_info *hw, int mtu)
|
||||
+static void dwmac100_core_init(struct mac_device_info *hw,
|
||||
+ struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
- writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
|
||||
+ value |= MAC_CORE_INIT;
|
||||
+
|
||||
+ /* Clear ASTP bit because Ethernet switch tagging formats such as
|
||||
+ * Broadcom tags can look like invalid LLC/SNAP packets and cause the
|
||||
+ * hardware to truncate packets on reception.
|
||||
+ */
|
||||
+ if (netdev_uses_dsa(dev))
|
||||
+ value &= ~MAC_CONTROL_ASTP;
|
||||
+
|
||||
+ writel(value, ioaddr + MAC_CONTROL);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
index f3ed8f7853eb4..ed222b20fcf19 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
@@ -17,16 +17,26 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
+#include <net/dsa.h>
|
||||
#include "stmmac_pcs.h"
|
||||
#include "dwmac4.h"
|
||||
|
||||
-static void dwmac4_core_init(struct mac_device_info *hw, int mtu)
|
||||
+static void dwmac4_core_init(struct mac_device_info *hw,
|
||||
+ struct net_device *dev)
|
||||
{
|
||||
void __iomem *ioaddr = hw->pcsr;
|
||||
u32 value = readl(ioaddr + GMAC_CONFIG);
|
||||
+ int mtu = dev->mtu;
|
||||
|
||||
value |= GMAC_CORE_INIT;
|
||||
|
||||
+ /* Clear ACS bit because Ethernet switch tagging formats such as
|
||||
+ * Broadcom tags can look like invalid LLC/SNAP packets and cause the
|
||||
+ * hardware to truncate packets on reception.
|
||||
+ */
|
||||
+ if (netdev_uses_dsa(dev))
|
||||
+ value &= ~GMAC_CONFIG_ACS;
|
||||
+
|
||||
if (mtu > 1500)
|
||||
value |= GMAC_CONFIG_2K;
|
||||
if (mtu > 2000)
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
index f99f14c35063d..7ad841434ec8d 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
||||
@@ -2527,7 +2527,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
|
||||
}
|
||||
|
||||
/* Initialize the MAC Core */
|
||||
- priv->hw->mac->core_init(priv->hw, dev->mtu);
|
||||
+ priv->hw->mac->core_init(priv->hw, dev);
|
||||
|
||||
/* Initialize MTL*/
|
||||
if (priv->synopsys_id >= DWMAC_CORE_4_00)
|
@ -0,0 +1,59 @@
|
||||
From d8f8b9542a4d8d560c0292a492f4edd922dd4ece Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Date: Mon, 22 Jan 2018 16:59:50 +0100
|
||||
Subject: [PATCH] net: stmmac: do not use a bitwise AND operator with a bool
|
||||
operand
|
||||
|
||||
Doing a bitwise AND between a bool and an int is generally not a good idea.
|
||||
The bool will be promoted to an int with value 0 or 1,
|
||||
the int is generally regarded as true with a non-zero value,
|
||||
thus ANDing them has the potential to yield an undesired result.
|
||||
|
||||
This commit fixes the following smatch warnings:
|
||||
|
||||
drivers/net/ethernet/stmicro/stmmac/enh_desc.c:344 enh_desc_prepare_tx_desc() warn: maybe use && instead of &
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c:337 dwmac4_rd_prepare_tx_desc() warn: maybe use && instead of &
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c:380 dwmac4_rd_prepare_tso_tx_desc() warn: maybe use && instead of &
|
||||
|
||||
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 4 ++--
|
||||
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 2 +-
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
|
||||
index 2fd8456999f69..c728ffa095de0 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
|
||||
@@ -334,7 +334,7 @@ static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
if (tx_own)
|
||||
tdes3 |= TDES3_OWN;
|
||||
|
||||
- if (is_fs & tx_own)
|
||||
+ if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
@@ -377,7 +377,7 @@ static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
|
||||
if (tx_own)
|
||||
tdes3 |= TDES3_OWN;
|
||||
|
||||
- if (is_fs & tx_own)
|
||||
+ if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
|
||||
index b47cb5c4da513..6768a25b6aa09 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
|
||||
@@ -341,7 +341,7 @@ static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
if (tx_own)
|
||||
tdes0 |= ETDES0_OWN;
|
||||
|
||||
- if (is_fs & tx_own)
|
||||
+ if (is_fs && tx_own)
|
||||
/* When the own bit, for the first frame, has to be set, all
|
||||
* descriptors for the same frame has to be set before, to
|
||||
* avoid race condition.
|
@ -0,0 +1,46 @@
|
||||
From e879b7ab3739d8f9990961fc7df2f63861bd780b Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Date: Fri, 9 Feb 2018 17:22:46 +0100
|
||||
Subject: [PATCH] net: stmmac: rename GMAC_INT_DEFAULT_MASK for dwmac4
|
||||
|
||||
GMAC_INT_DEFAULT_MASK is written to the interrupt enable register.
|
||||
In previous versions of the IP (e.g. dwmac1000), this register was
|
||||
instead an interrupt mask register.
|
||||
To improve clarity and reflect reality, rename GMAC_INT_DEFAULT_MASK
|
||||
to GMAC_INT_DEFAULT_ENABLE.
|
||||
|
||||
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 2 +-
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 4 ++--
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
index 789dad8a07b5c..7761a26ec9c56 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
|
||||
@@ -98,7 +98,7 @@
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
|
||||
GMAC_INT_PCS_ANE)
|
||||
|
||||
-#define GMAC_INT_DEFAULT_MASK (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
|
||||
+#define GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
|
||||
|
||||
enum dwmac4_irq_status {
|
||||
time_stamp_irq = 0x00001000,
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
index 1e0a7668b7529..6badc63d8e6d3 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
@@ -61,8 +61,8 @@ static void dwmac4_core_init(struct mac_device_info *hw,
|
||||
|
||||
writel(value, ioaddr + GMAC_CONFIG);
|
||||
|
||||
- /* Mask GMAC interrupts */
|
||||
- value = GMAC_INT_DEFAULT_MASK;
|
||||
+ /* Enable GMAC interrupts */
|
||||
+ value = GMAC_INT_DEFAULT_ENABLE;
|
||||
if (hw->pmt)
|
||||
value |= GMAC_INT_PMT_EN;
|
||||
if (hw->pcs)
|
@ -0,0 +1,49 @@
|
||||
From 1029117127540fef4edcf4f0887dc3e1f7d5adb2 Mon Sep 17 00:00:00 2001
|
||||
From: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Date: Fri, 9 Feb 2018 17:22:47 +0100
|
||||
Subject: [PATCH] net: stmmac: remove redundant enable of PMT irq
|
||||
|
||||
For dwmac4, GMAC_INT_DEFAULT_ENABLE already includes
|
||||
GMAC_INT_PMT_EN, so it is redundant to check if hw->pmt
|
||||
is set, and if so, setting the bit again.
|
||||
|
||||
For dwmac1000, GMAC_INT_DEFAULT_MASK does not include
|
||||
GMAC_INT_DISABLE_PMT, so it is redundant to check if
|
||||
hw->pmt is set, and if so, clearing an already cleared bit.
|
||||
|
||||
Improve code readability by removing this redundant code.
|
||||
|
||||
Signed-off-by: Niklas Cassel <niklas.cassel@axis.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 2 --
|
||||
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 3 +--
|
||||
2 files changed, 1 insertion(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
|
||||
index 540d21786a43b..ef10baf141862 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
|
||||
@@ -74,8 +74,6 @@ static void dwmac1000_core_init(struct mac_device_info *hw,
|
||||
/* Mask GMAC interrupts */
|
||||
value = GMAC_INT_DEFAULT_MASK;
|
||||
|
||||
- if (hw->pmt)
|
||||
- value &= ~GMAC_INT_DISABLE_PMT;
|
||||
if (hw->pcs)
|
||||
value &= ~GMAC_INT_DISABLE_PCS;
|
||||
|
||||
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
index 6badc63d8e6d3..63795ecafc8dc 100644
|
||||
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
||||
@@ -63,8 +63,7 @@ static void dwmac4_core_init(struct mac_device_info *hw,
|
||||
|
||||
/* Enable GMAC interrupts */
|
||||
value = GMAC_INT_DEFAULT_ENABLE;
|
||||
- if (hw->pmt)
|
||||
- value |= GMAC_INT_PMT_EN;
|
||||
+
|
||||
if (hw->pcs)
|
||||
value |= GMAC_PCS_IRQ_DEFAULT;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user