update meson patches for 6.9 kernel

This commit is contained in:
kernelzru
2024-06-06 13:59:11 +03:00
committed by Igor Pecovnik
parent bda1f6c385
commit 6310f60617
53 changed files with 7016 additions and 4461 deletions

View File

@@ -4893,6 +4893,7 @@ CONFIG_DRM_DW_HDMI=y
# CONFIG_DRM_LOGICVC is not set
CONFIG_DRM_MESON=y
CONFIG_DRM_MESON_DW_HDMI=y
CONFIG_DRM_MESON_TRANSWITCH_HDMI=y
# CONFIG_DRM_MESON_DW_MIPI_DSI is not set
# CONFIG_DRM_ARCPGU is not set
# CONFIG_DRM_BOCHS is not set
@@ -6910,6 +6911,7 @@ CONFIG_GENERIC_PHY=y
# CONFIG_PHY_CAN_TRANSCEIVER is not set
CONFIG_PHY_MESON8_HDMI_TX=y
CONFIG_PHY_MESON8B_USB2=y
CONFIG_PHY_MESON_CVBS_DAC=y
# CONFIG_PHY_MESON_GXL_USB2 is not set
# CONFIG_PHY_MESON_G12A_MIPI_DPHY_ANALOG is not set
# CONFIG_PHY_MESON_G12A_USB2 is not set

View File

@@ -0,0 +1,47 @@
From 85409ae3c08b4b1aedc80d35f0afd6832cfe5d1f Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 16 Jun 2021 20:34:01 +0200
Subject: [PATCH 07/96] dt-bindings: phy: meson8b-usb2: Add support for reading
the ID signal
The first USB PHY on Amlogic Meson8/8b/8m2/GXBB SoCs is OTG capable.
This means that the USB "ID" signal is routed to the PHY. Add support
for the gpio-controller and #gpio-cells properties so the value of
the "ID" signal can be read as a GPIO (from the PHY) for example by
an "gpio-usb-b-connector".
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../bindings/phy/amlogic,meson8b-usb2-phy.yaml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml
index df68bfe5f..be722a235 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml
@@ -6,6 +6,10 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY
+description: |
+ OTG capable PHYs have the USB "ID" signal routed to them.
+ This can be read out via the PHY-provided GPIO controller.
+
maintainers:
- Martin Blumenstingl <martin.blumenstingl@googlemail.com>
@@ -31,6 +35,11 @@ properties:
- const: usb_general
- const: usb
+ '#gpio-cells':
+ const: 2
+
+ gpio-controller: true
+
resets:
minItems: 1
--
2.45.1

View File

@@ -0,0 +1,103 @@
From fa852523a5da72615695668ef4d354b6af2cae83 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 3 May 2020 21:40:27 +0200
Subject: [PATCH 08/96] phy: amlogic: meson8b-usb2: Add support for reading the
"ID" signal
The first USB PHY on Amlogic Meson8/8b/8m2/GXBB SoCs is OTG capable.
This means that the USB "ID" signal is routed to the PHY. Add support
for the gpio-controller and #gpio-cells properties so the value of
the "ID" signal can be read as a GPIO (from the PHY) for example by
the usb-conn-gpio driver.
The registers also have a bit for the VBUS signal. That either is not
wired in hardware inside the SoC silicon or not wired on the boards
(e.g. Odroid-C1), which is why it's value is not exposed for now.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/phy/amlogic/phy-meson8b-usb2.c | 42 +++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c
index d63147c41..d3d0bd367 100644
--- a/drivers/phy/amlogic/phy-meson8b-usb2.c
+++ b/drivers/phy/amlogic/phy-meson8b-usb2.c
@@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -127,6 +128,7 @@ struct phy_meson8b_usb2_priv {
struct clk *clk_usb_general;
struct clk *clk_usb;
struct reset_control *reset;
+ struct gpio_chip gpiochip;
const struct phy_meson8b_usb2_match_data *match;
};
@@ -236,12 +238,44 @@ static const struct phy_ops phy_meson8b_usb2_ops = {
.owner = THIS_MODULE,
};
+static int phy_meson8b_usb2_id_gpio_get_direction(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_IN;
+}
+
+static int phy_meson8b_usb2_id_gpio_get_value(struct gpio_chip *gc,
+ unsigned int offset)
+{
+ struct phy_meson8b_usb2_priv *priv = gpiochip_get_data(gc);
+ unsigned int val;
+
+ regmap_read(priv->regmap, REG_ADP_BC, &val);
+
+ return (val & REG_ADP_BC_ID_DIG) ? 1 : 0;
+}
+
+static int phy_meson8b_usb2_id_gpiochip_add(struct device *dev,
+ struct phy_meson8b_usb2_priv *priv)
+{
+ priv->gpiochip.label = dev_name(dev);
+ priv->gpiochip.parent = dev;
+ priv->gpiochip.get_direction = phy_meson8b_usb2_id_gpio_get_direction;
+ priv->gpiochip.get = phy_meson8b_usb2_id_gpio_get_value;
+ priv->gpiochip.of_gpio_n_cells = 2;
+ priv->gpiochip.base = -1;
+ priv->gpiochip.ngpio = 1;
+
+ return devm_gpiochip_add_data(dev, &priv->gpiochip, priv);
+}
+
static int phy_meson8b_usb2_probe(struct platform_device *pdev)
{
struct phy_meson8b_usb2_priv *priv;
- struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *base;
+ struct phy *phy;
+ int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -280,6 +314,12 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev)
return -EINVAL;
}
+ if (device_property_read_bool(&pdev->dev, "gpio-controller")) {
+ ret = phy_meson8b_usb2_id_gpiochip_add(&pdev->dev, priv);
+ if (ret)
+ return ret;
+ }
+
phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops);
if (IS_ERR(phy)) {
return dev_err_probe(&pdev->dev, PTR_ERR(phy),
--
2.45.1

View File

@@ -0,0 +1,147 @@
From 8d8783f1098d154b6beb13fb694cf932dbf43e43 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 16 Jun 2021 21:07:50 +0200
Subject: [PATCH 09/96] usb: common: usb-conn-gpio: Fall back to polling the
GPIO
On some SoCs (for example: Amlogic Meson8/8b/8m2 and GXBB) the ID GPIO
cannot generate an interrupt. Fall back to polling the GPIO(s) in that
case.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/usb/common/usb-conn-gpio.c | 76 +++++++++++++++++++-----------
1 file changed, 48 insertions(+), 28 deletions(-)
diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c
index 501e8bc97..b0b19e026 100644
--- a/drivers/usb/common/usb-conn-gpio.c
+++ b/drivers/usb/common/usb-conn-gpio.c
@@ -23,6 +23,7 @@
#define USB_GPIO_DEB_MS 20 /* ms */
#define USB_GPIO_DEB_US ((USB_GPIO_DEB_MS) * 1000) /* us */
+#define USB_GPIO_POLL_MS 1000
#define USB_CONN_IRQF \
(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT)
@@ -45,6 +46,23 @@ struct usb_conn_info {
bool initial_detection;
};
+static void usb_conn_queue_dwork(struct usb_conn_info *info,
+ unsigned long delay)
+{
+ queue_delayed_work(system_power_efficient_wq, &info->dw_det, delay);
+}
+
+static void usb_conn_gpio_start_polling(struct usb_conn_info *info)
+{
+ usb_conn_queue_dwork(info, msecs_to_jiffies(USB_GPIO_POLL_MS));
+}
+
+static bool usb_conn_gpio_needs_polling(struct usb_conn_info *info)
+{
+ /* We need to poll if one of the GPIOs cannot generate an IRQ. */
+ return info->id_irq < 0 || info->vbus_irq < 0;
+}
+
/*
* "DEVICE" = VBUS and "HOST" = !ID, so we have:
* Both "DEVICE" and "HOST" can't be set as active at the same time
@@ -88,7 +106,10 @@ static void usb_conn_detect_cable(struct work_struct *work)
usb_role_string(info->last_role), usb_role_string(role), id, vbus);
if (!info->initial_detection && info->last_role == role) {
- dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
+ if (usb_conn_gpio_needs_polling(info))
+ usb_conn_gpio_start_polling(info);
+ else
+ dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
return;
}
@@ -114,12 +135,9 @@ static void usb_conn_detect_cable(struct work_struct *work)
regulator_is_enabled(info->vbus) ? "enabled" : "disabled");
power_supply_changed(info->charger);
-}
-static void usb_conn_queue_dwork(struct usb_conn_info *info,
- unsigned long delay)
-{
- queue_delayed_work(system_power_efficient_wq, &info->dw_det, delay);
+ if (usb_conn_gpio_needs_polling(info))
+ usb_conn_gpio_start_polling(info);
}
static irqreturn_t usb_conn_isr(int irq, void *dev_id)
@@ -226,34 +244,34 @@ static int usb_conn_probe(struct platform_device *pdev)
if (info->id_gpiod) {
info->id_irq = gpiod_to_irq(info->id_gpiod);
if (info->id_irq < 0) {
- dev_err(dev, "failed to get ID IRQ\n");
- ret = info->id_irq;
- goto put_role_sw;
- }
-
- ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
- usb_conn_isr, USB_CONN_IRQF,
- pdev->name, info);
- if (ret < 0) {
- dev_err(dev, "failed to request ID IRQ\n");
- goto put_role_sw;
+ dev_info(dev,
+ "failed to get ID IRQ - falling back to polling\n");
+ } else {
+ ret = devm_request_threaded_irq(dev, info->id_irq,
+ NULL, usb_conn_isr,
+ USB_CONN_IRQF,
+ pdev->name, info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request ID IRQ\n");
+ goto put_role_sw;
+ }
}
}
if (info->vbus_gpiod) {
info->vbus_irq = gpiod_to_irq(info->vbus_gpiod);
if (info->vbus_irq < 0) {
- dev_err(dev, "failed to get VBUS IRQ\n");
- ret = info->vbus_irq;
- goto put_role_sw;
- }
-
- ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
- usb_conn_isr, USB_CONN_IRQF,
- pdev->name, info);
- if (ret < 0) {
- dev_err(dev, "failed to request VBUS IRQ\n");
- goto put_role_sw;
+ dev_info(dev,
+ "failed to get VBUS IRQ - falling back to polling\n");
+ } else {
+ ret = devm_request_threaded_irq(dev, info->vbus_irq,
+ NULL, usb_conn_isr,
+ USB_CONN_IRQF,
+ pdev->name, info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request VBUS IRQ\n");
+ goto put_role_sw;
+ }
}
}
@@ -300,6 +318,8 @@ static int __maybe_unused usb_conn_suspend(struct device *dev)
if (info->vbus_gpiod)
disable_irq(info->vbus_irq);
+ cancel_delayed_work_sync(&info->dw_det);
+
pinctrl_pm_select_sleep_state(dev);
return 0;
--
2.45.1

View File

@@ -0,0 +1,49 @@
From d7166eaf19e263a1b6dd551f1b5c40b86524b4d6 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 4 Jul 2020 21:04:29 +0200
Subject: [PATCH 10/96] usb: dwc2: register child (USB connector) devices
Populate the child devices/nodes of the dwc2 controller. Typically these
are USB connectors with a compatible string (and additional properties)
like "gpio-usb-b-connector".
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/usb/dwc2/platform.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index b1d48019e..d56c1ea5b 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -12,6 +12,7 @@
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
@@ -620,6 +621,19 @@ static int dwc2_driver_probe(struct platform_device *dev)
}
}
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
+
+ retval = devm_of_platform_populate(&dev->dev);
+ if (retval) {
+ dev_err(hsotg->dev,
+ "Failed to create child devices/connectors for %p\n",
+ dev->dev.of_node);
+
+ if (hsotg->gadget_enabled)
+ dwc2_hsotg_remove(hsotg);
+
+ goto error_debugfs;
+ }
+
return 0;
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \
--
2.45.1

View File

@@ -0,0 +1,30 @@
From 8a559e2ff9aa875656c3c62df16dedc84f68c2b7 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 16 Jun 2021 20:38:07 +0200
Subject: [PATCH 11/96] ARM: dts: meson: Add GPIO controller capabilities to
the first USB PHY
This is needed for boards that implement OTG functionality to read out
the value of the "ID" signal (e.g. on Micro USB connectors).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson.dtsi b/arch/arm/boot/dts/amlogic/meson.dtsi
index 8cb0fc78b..0e7756c95 100644
--- a/arch/arm/boot/dts/amlogic/meson.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson.dtsi
@@ -124,6 +124,8 @@ usb0_phy: phy@8800 {
compatible = "amlogic,meson-mx-usb2-phy";
#phy-cells = <0>;
reg = <0x8800 0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
status = "disabled";
};
--
2.45.1

View File

@@ -0,0 +1,75 @@
From ebc6d5206b98d516e34304a42898d7733301cc96 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 4 May 2020 00:16:00 +0200
Subject: [PATCH 12/96] ARM: dts: meson8b: odroidc1: Enable the Micro USB OTG
connector
Enable &usb0 which is routed to the Micro USB connector. The port
supports OTG modes and the role switch is implemented by reading out the
"ID" signal from &usb0_phy.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../arm/boot/dts/amlogic/meson8b-odroidc1.dts | 34 ++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts
index 941682844..eaf89638c 100644
--- a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts
+++ b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts
@@ -93,6 +93,20 @@ rtc32k_xtal: rtc32k-xtal-clk {
#clock-cells = <0>;
};
+ usb0_vbus: regulator-usb0-vbus {
+ /* Richtek RT9715EGB */
+ compatible = "regulator-fixed";
+
+ regulator-name = "USB0_VBUS";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+
+ vin-supply = <&p5v0>;
+
+ gpio = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
vcc_1v8: regulator-vcc-1v8 {
/*
* RICHTEK RT9179 configured for a fixed output voltage of
@@ -363,8 +377,18 @@ &uart_AO {
pinctrl-names = "default";
};
-&usb1_phy {
+&usb0 {
status = "okay";
+
+ dr_mode = "otg";
+ usb-role-switch;
+
+ connector {
+ compatible = "gpio-usb-b-connector", "usb-b-connector";
+ type = "micro";
+ id-gpios = <&usb0_phy 0 GPIO_ACTIVE_HIGH>;
+ vbus-supply = <&usb0_vbus>;
+ };
};
&usb1 {
@@ -381,3 +405,11 @@ hub@1 {
reset-gpio = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>;
};
};
+
+&usb0_phy {
+ status = "okay";
+};
+
+&usb1_phy {
+ status = "okay";
+};
--
2.45.1

View File

@@ -0,0 +1,106 @@
From 84f7776a36cf1b7bae65498c93dd7850efa0c12b Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 11 Oct 2021 23:37:19 +0200
Subject: [PATCH 13/96] dt-bindings: phy: Add bindings for the Amlogic Meson
CVBS DAC
Amlogic Meson SoCs embed a Composite Video Baseband Signal DAC. Add the
bindings for this IP.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../phy/amlogic,meson-cvbs-dac-phy.yaml | 82 +++++++++++++++++++
1 file changed, 82 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/amlogic,meson-cvbs-dac-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-cvbs-dac-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-cvbs-dac-phy.yaml
new file mode 100644
index 000000000..906a69505
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson-cvbs-dac-phy.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/amlogic,meson-cvbs-dac-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic Meson Composite Video Baseband Signal DAC
+
+maintainers:
+ - Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+
+description: |+
+ The CVBS DAC node should be the child of a syscon node with the
+ required property:
+
+ compatible = "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
+
+ Refer to the bindings described in
+ Documentation/devicetree/bindings/mfd/syscon.yaml
+
+properties:
+ $nodename:
+ pattern: "^video-dac@[0-9a-f]+$"
+
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - amlogic,meson8-cvbs-dac
+ - amlogic,meson8b-cvbs-dac
+ - amlogic,meson-gxbb-cvbs-dac
+ - amlogic,meson-gxl-cvbs-dac
+ - amlogic,meson-g12a-cvbs-dac
+ - const: amlogic,meson-cvbs-dac
+ - const: amlogic,meson-cvbs-dac
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+
+ nvmem-cells:
+ minItems: 1
+
+ nvmem-cell-names:
+ items:
+ - const: cvbs_trimming
+
+ "#phy-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ video-dac@2f4 {
+ compatible = "amlogic,meson8-cvbs-dac", "amlogic,meson-cvbs-dac";
+ reg = <0x2f4 0x8>;
+
+ #phy-cells = <0>;
+
+ clocks = <&vdac_clock>;
+
+ nvmem-cells = <&cvbs_trimming>;
+ nvmem-cell-names = "cvbs_trimming";
+ };
+ - |
+ video-dac@2ec {
+ compatible = "amlogic,meson-g12a-cvbs-dac", "amlogic,meson-cvbs-dac";
+ reg = <0x2ec 0x8>;
+
+ #phy-cells = <0>;
+
+ clocks = <&vdac_clock>;
+ };
--
2.45.1

View File

@@ -0,0 +1,447 @@
From a8af3998b655e87d5a10380584d2e80a93129195 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 11 Oct 2021 23:05:25 +0200
Subject: [PATCH 14/96] phy: amlogic: Add a new driver for the CVBS DAC (CVBS
PHY)
Amlogic Meson SoCs embed a CVBS DAC which converts the signal from the
VPU to analog. The IP has evolved over time with the SoC generations:
- Meson8/8b/8m2 has per-chip calibrated data for the CDAC_GSW register
- GXBB is overall similar to Meson8/8b/8m2 except that it doesn't have
per-chip calibration data and uses 0x0 in CDAC_GSW always
- GXL/GXM are overall similar to GXBB but require a CDAC_VREF_ADJ value
of 0xf (of which the actual meaning is unknown)
- G12A/G12B/SM1 use different register offsets and different values for
CDAC_CTRL_RESV2, CDAC_VREF_ADJ and CDAC_RL_ADJ. Like other SoCs from
GXBB onwards they don't need any per-chip data.
For backwards compatibility with old .dtbs the driver gets
platform_device_id's so the VPU driver can register the PHY as platform
device if not provided via .dtb.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/phy/amlogic/Kconfig | 10 +
drivers/phy/amlogic/Makefile | 1 +
drivers/phy/amlogic/phy-meson-cvbs-dac.c | 376 +++++++++++++++++++++++
3 files changed, 387 insertions(+)
create mode 100644 drivers/phy/amlogic/phy-meson-cvbs-dac.c
diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig
index ce7ba3eb2..671435b60 100644
--- a/drivers/phy/amlogic/Kconfig
+++ b/drivers/phy/amlogic/Kconfig
@@ -25,6 +25,16 @@ config PHY_MESON8B_USB2
Meson8b and GXBB SoCs.
If unsure, say N.
+config PHY_MESON_CVBS_DAC
+ tristate "Amlogic Meson CVBS DAC PHY driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ depends on OF
+ select MFD_SYSCON
+ help
+ Enable this to support the CVBS DAC (PHY) found in Amlogic
+ Meson 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 91e3b9790..f6c38f738 100644
--- a/drivers/phy/amlogic/Makefile
+++ b/drivers/phy/amlogic/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_PHY_MESON8_HDMI_TX) += phy-meson8-hdmi-tx.o
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
+obj-$(CONFIG_PHY_MESON_CVBS_DAC) += phy-meson-cvbs-dac.o
obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o
obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o
obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE) += phy-meson-g12a-usb3-pcie.o
diff --git a/drivers/phy/amlogic/phy-meson-cvbs-dac.c b/drivers/phy/amlogic/phy-meson-cvbs-dac.c
new file mode 100644
index 000000000..10edfb120
--- /dev/null
+++ b/drivers/phy/amlogic/phy-meson-cvbs-dac.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/property.h>
+#include <linux/mfd/syscon.h>
+#include <linux/nvmem-consumer.h>
+
+#define HHI_VDAC_CNTL0_MESON8 0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1_MESON8 0x2F8 /* 0xbe offset in data sheet */
+
+#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */
+
+enum phy_meson_cvbs_dac_reg {
+ MESON_CDAC_CTRL_RESV1,
+ MESON_CDAC_CTRL_RESV2,
+ MESON_CDAC_VREF_ADJ,
+ MESON_CDAC_RL_ADJ,
+ MESON_CDAC_CLK_PHASE_SEL,
+ MESON_CDAC_DRIVER_ADJ,
+ MESON_CDAC_EXT_VREF_EN,
+ MESON_CDAC_BIAS_C,
+ MESON_VDAC_CNTL0_RESERVED,
+ MESON_CDAC_GSW,
+ MESON_CDAC_PWD,
+ MESON_VDAC_CNTL1_RESERVED,
+ MESON_CVBS_DAC_NUM_REGS
+};
+
+struct phy_meson_cvbs_dac_data {
+ const struct reg_field *reg_fields;
+ u8 cdac_ctrl_resv2_enable_val;
+ u8 cdac_vref_adj_enable_val;
+ u8 cdac_rl_adj_enable_val;
+ u8 cdac_pwd_disable_val;
+ bool needs_cvbs_trimming_nvmem_cell;
+};
+
+struct phy_meson_cvbs_dac_priv {
+ struct regmap_field *regs[MESON_CVBS_DAC_NUM_REGS];
+ const struct phy_meson_cvbs_dac_data *data;
+ u8 cdac_gsw_enable_val;
+};
+
+static const struct reg_field phy_meson8_cvbs_dac_reg_fields[] = {
+ [MESON_CDAC_CTRL_RESV1] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 0, 7),
+ [MESON_CDAC_CTRL_RESV2] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 8, 15),
+ [MESON_CDAC_VREF_ADJ] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 16, 20),
+ [MESON_CDAC_RL_ADJ] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 21, 23),
+ [MESON_CDAC_CLK_PHASE_SEL] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 24, 24),
+ [MESON_CDAC_DRIVER_ADJ] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 25, 25),
+ [MESON_CDAC_EXT_VREF_EN] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 26, 26),
+ [MESON_CDAC_BIAS_C] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 27, 27),
+ [MESON_VDAC_CNTL0_RESERVED] = REG_FIELD(HHI_VDAC_CNTL0_MESON8, 28, 31),
+ [MESON_CDAC_GSW] = REG_FIELD(HHI_VDAC_CNTL1_MESON8, 0, 2),
+ [MESON_CDAC_PWD] = REG_FIELD(HHI_VDAC_CNTL1_MESON8, 3, 3),
+ [MESON_VDAC_CNTL1_RESERVED] = REG_FIELD(HHI_VDAC_CNTL1_MESON8, 4, 31),
+};
+
+static const struct reg_field phy_meson_g12a_cvbs_dac_reg_fields[] = {
+ [MESON_CDAC_CTRL_RESV1] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 0, 7),
+ [MESON_CDAC_CTRL_RESV2] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 8, 15),
+ [MESON_CDAC_VREF_ADJ] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 16, 20),
+ [MESON_CDAC_RL_ADJ] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 21, 23),
+ [MESON_CDAC_CLK_PHASE_SEL] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 24, 24),
+ [MESON_CDAC_DRIVER_ADJ] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 25, 25),
+ [MESON_CDAC_EXT_VREF_EN] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 26, 26),
+ [MESON_CDAC_BIAS_C] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 27, 27),
+ [MESON_VDAC_CNTL0_RESERVED] = REG_FIELD(HHI_VDAC_CNTL0_G12A, 28, 31),
+ [MESON_CDAC_GSW] = REG_FIELD(HHI_VDAC_CNTL1_G12A, 0, 2),
+ [MESON_CDAC_PWD] = REG_FIELD(HHI_VDAC_CNTL1_G12A, 3, 3),
+ [MESON_VDAC_CNTL1_RESERVED] = REG_FIELD(HHI_VDAC_CNTL1_G12A, 4, 31),
+};
+
+static const struct phy_meson_cvbs_dac_data phy_meson8_cvbs_dac_data = {
+ .reg_fields = phy_meson8_cvbs_dac_reg_fields,
+ .cdac_ctrl_resv2_enable_val = 0x0,
+ .cdac_vref_adj_enable_val = 0x0,
+ .cdac_rl_adj_enable_val = 0x0,
+ .cdac_pwd_disable_val = 0x1,
+ .needs_cvbs_trimming_nvmem_cell = true,
+};
+
+static const struct phy_meson_cvbs_dac_data phy_meson_gxbb_cvbs_dac_data = {
+ .reg_fields = phy_meson8_cvbs_dac_reg_fields,
+ .cdac_ctrl_resv2_enable_val = 0x0,
+ .cdac_vref_adj_enable_val = 0x0,
+ .cdac_rl_adj_enable_val = 0x0,
+ .cdac_pwd_disable_val = 0x1,
+ .needs_cvbs_trimming_nvmem_cell = false,
+};
+
+static const struct phy_meson_cvbs_dac_data phy_meson_gxl_cvbs_dac_data = {
+ .reg_fields = phy_meson8_cvbs_dac_reg_fields,
+ .cdac_ctrl_resv2_enable_val = 0x0,
+ .cdac_vref_adj_enable_val = 0xf,
+ .cdac_rl_adj_enable_val = 0x0,
+ .cdac_pwd_disable_val = 0x1,
+ .needs_cvbs_trimming_nvmem_cell = false,
+};
+
+static const struct phy_meson_cvbs_dac_data phy_meson_g12a_cvbs_dac_data = {
+ .reg_fields = phy_meson_g12a_cvbs_dac_reg_fields,
+ .cdac_ctrl_resv2_enable_val = 0x60,
+ .cdac_vref_adj_enable_val = 0x10,
+ .cdac_rl_adj_enable_val = 0x4,
+ .cdac_pwd_disable_val = 0x0,
+ .needs_cvbs_trimming_nvmem_cell = false,
+};
+
+static int phy_meson_cvbs_dac_power_on(struct phy *phy)
+{
+ struct phy_meson_cvbs_dac_priv *priv = phy_get_drvdata(phy);
+
+ regmap_field_write(priv->regs[MESON_CDAC_CTRL_RESV1], 0x1);
+ regmap_field_write(priv->regs[MESON_CDAC_CTRL_RESV2],
+ priv->data->cdac_ctrl_resv2_enable_val);
+ regmap_field_write(priv->regs[MESON_CDAC_VREF_ADJ],
+ priv->data->cdac_vref_adj_enable_val);
+ regmap_field_write(priv->regs[MESON_CDAC_RL_ADJ],
+ priv->data->cdac_rl_adj_enable_val);
+ regmap_field_write(priv->regs[MESON_CDAC_GSW],
+ priv->cdac_gsw_enable_val);
+ regmap_field_write(priv->regs[MESON_CDAC_PWD], 0x0);
+
+ return 0;
+}
+
+static int phy_meson_cvbs_dac_power_off(struct phy *phy)
+{
+ struct phy_meson_cvbs_dac_priv *priv = phy_get_drvdata(phy);
+
+ regmap_field_write(priv->regs[MESON_CDAC_CTRL_RESV1], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_CTRL_RESV2], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_VREF_ADJ], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_RL_ADJ], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_GSW], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_PWD],
+ priv->data->cdac_pwd_disable_val);
+
+ return 0;
+}
+
+static int phy_meson_cvbs_dac_init(struct phy *phy)
+{
+ struct phy_meson_cvbs_dac_priv *priv = phy_get_drvdata(phy);
+
+ regmap_field_write(priv->regs[MESON_CDAC_CLK_PHASE_SEL], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_DRIVER_ADJ], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_EXT_VREF_EN], 0x0);
+ regmap_field_write(priv->regs[MESON_CDAC_BIAS_C], 0x0);
+ regmap_field_write(priv->regs[MESON_VDAC_CNTL0_RESERVED], 0x0);
+ regmap_field_write(priv->regs[MESON_VDAC_CNTL1_RESERVED], 0x0);
+
+ return phy_meson_cvbs_dac_power_off(phy);
+}
+
+static const struct phy_ops phy_meson_cvbs_dac_ops = {
+ .init = phy_meson_cvbs_dac_init,
+ .power_on = phy_meson_cvbs_dac_power_on,
+ .power_off = phy_meson_cvbs_dac_power_off,
+ .owner = THIS_MODULE,
+};
+
+static u8 phy_meson_cvbs_trimming_version(u8 trimming1)
+{
+ if ((trimming1 & 0xf0) == 0xa0)
+ return 5;
+ else if ((trimming1 & 0xf0) == 0x40)
+ return 2;
+ else if ((trimming1 & 0xc0) == 0x80)
+ return 1;
+ else if ((trimming1 & 0xc0) == 0x00)
+ return 0;
+ else
+ return 0xff;
+}
+
+static int phy_meson_cvbs_read_trimming(struct device *dev,
+ struct phy_meson_cvbs_dac_priv *priv)
+{
+ struct nvmem_cell *cell;
+ u8 *trimming;
+ size_t len;
+
+ cell = devm_nvmem_cell_get(dev, "cvbs_trimming");
+ if (IS_ERR(cell))
+ return dev_err_probe(dev, PTR_ERR(cell),
+ "Failed to get the 'cvbs_trimming' nvmem-cell\n");
+
+ trimming = nvmem_cell_read(cell, &len);
+ if (IS_ERR(trimming)) {
+ /*
+ * TrustZone firmware may block access to the CVBS trimming
+ * data stored in the eFuse. On those devices the trimming data
+ * is stored in the u-boot environment. However, the known
+ * examples of trimming data in the u-boot environment are all
+ * zero.
+ */
+ dev_dbg(dev,
+ "Failed to read the 'cvbs_trimming' nvmem-cell - falling back to a default value\n");
+ priv->cdac_gsw_enable_val = 0x0;
+ return 0;
+ }
+
+ if (len != 2) {
+ kfree(trimming);
+ return dev_err_probe(dev, -EINVAL,
+ "Read the 'cvbs_trimming' nvmem-cell with invalid length\n");
+ }
+
+ switch (phy_meson_cvbs_trimming_version(trimming[1])) {
+ case 1:
+ case 2:
+ case 5:
+ priv->cdac_gsw_enable_val = trimming[0] & 0x7;
+ break;
+ default:
+ priv->cdac_gsw_enable_val = 0x0;
+ break;
+ }
+
+ kfree(trimming);
+
+ return 0;
+}
+
+static int phy_meson_cvbs_dac_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct phy_meson_cvbs_dac_priv *priv;
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct regmap *hhi;
+ struct phy *phy;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (np) {
+ priv->data = device_get_match_data(dev);
+ if (!priv->data)
+ return dev_err_probe(dev, -EINVAL,
+ "Could not find the OF match data\n");
+
+ hhi = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(hhi))
+ return dev_err_probe(dev, PTR_ERR(hhi),
+ "Failed to get the parent syscon\n");
+ } else {
+ const struct platform_device_id *pdev_id;
+
+ pdev_id = platform_get_device_id(pdev);
+ if (!pdev_id)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to find platform device ID\n");
+
+ priv->data = (void *)pdev_id->driver_data;
+ if (!priv->data)
+ return dev_err_probe(dev, -EINVAL,
+ "Could not find the platform driver data\n");
+
+ hhi = syscon_regmap_lookup_by_compatible("amlogic,meson-gx-hhi-sysctrl");
+ if (IS_ERR(hhi))
+ return dev_err_probe(dev, PTR_ERR(hhi),
+ "Failed to get the \"amlogic,meson-gx-hhi-sysctrl\" syscon\n");
+ }
+
+ if (priv->data->needs_cvbs_trimming_nvmem_cell) {
+ ret = phy_meson_cvbs_read_trimming(dev, priv);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_regmap_field_bulk_alloc(dev, hhi, priv->regs,
+ priv->data->reg_fields,
+ MESON_CVBS_DAC_NUM_REGS);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to create regmap fields\n");
+
+ phy = devm_phy_create(dev, np, &phy_meson_cvbs_dac_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ phy_set_drvdata(phy, priv);
+
+ if (np) {
+ phy_provider = devm_of_phy_provider_register(dev,
+ of_phy_simple_xlate);
+ ret = PTR_ERR_OR_ZERO(phy_provider);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to register PHY provider\n");
+ } else {
+ platform_set_drvdata(pdev, phy);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id phy_meson_cvbs_dac_of_match[] = {
+ {
+ .compatible = "amlogic,meson8-cvbs-dac",
+ .data = &phy_meson8_cvbs_dac_data,
+ },
+ {
+ .compatible = "amlogic,meson8b-cvbs-dac",
+ .data = &phy_meson8_cvbs_dac_data,
+ },
+ {
+ .compatible = "amlogic,meson-gxbb-cvbs-dac",
+ .data = &phy_meson_gxbb_cvbs_dac_data,
+ },
+ {
+ .compatible = "amlogic,meson-gxl-cvbs-dac",
+ .data = &phy_meson_gxl_cvbs_dac_data,
+ },
+ {
+ .compatible = "amlogic,meson-g12a-cvbs-dac",
+ .data = &phy_meson_g12a_cvbs_dac_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, phy_meson_cvbs_dac_of_match);
+
+/*
+ * The platform_device_id table is used for backwards compatibility with old
+ * .dtbs which don't have a CVBS DAC node (where the VPU DRM driver registers
+ * this as a platform device. Support for additional SoCs should only be added
+ * to the of_device_id table above.
+ */
+static const struct platform_device_id phy_meson_cvbs_dac_device_ids[] = {
+ {
+ .name = "meson-gxbb-cvbs-dac",
+ .driver_data = (kernel_ulong_t)&phy_meson_gxbb_cvbs_dac_data,
+ },
+ {
+ .name = "meson-gxl-cvbs-dac",
+ .driver_data = (kernel_ulong_t)&phy_meson_gxl_cvbs_dac_data,
+ },
+ {
+ .name = "meson-g12a-cvbs-dac",
+ .driver_data = (kernel_ulong_t)&phy_meson_g12a_cvbs_dac_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, phy_meson_cvbs_dac_device_ids);
+
+static struct platform_driver phy_meson_cvbs_dac_driver = {
+ .driver = {
+ .name = "phy-meson-cvbs-dac",
+ .of_match_table = phy_meson_cvbs_dac_of_match,
+ },
+ .id_table = phy_meson_cvbs_dac_device_ids,
+ .probe = phy_meson_cvbs_dac_probe,
+};
+module_platform_driver(phy_meson_cvbs_dac_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Amlogic Meson CVBS DAC driver");
+MODULE_LICENSE("GPL v2");
--
2.45.1

View File

@@ -0,0 +1,49 @@
From 3b2d4e35f9726027f7fe3c0c10dae8e86169ba39 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 20 Oct 2021 22:19:25 +0200
Subject: [PATCH 15/96] dt-bindings: display: meson-vpu: Add the CVBS DAC
properties
The CVBS DAC converts the digital video signal to the (analog) composite
video baseband signal (CVBS). This DAC is part of the HHI registers.
Add the phy and phy-names property to describe the relation between the
VPU (which outputs the digital signal) and the CVBS DAC.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../bindings/display/amlogic,meson-vpu.yaml | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
index cb0a90f02..c9ab01434 100644
--- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
@@ -82,6 +82,15 @@ properties:
description: should point to a canvas provider node
$ref: /schemas/types.yaml#/definitions/phandle
+ phys:
+ maxItems: 1
+ description:
+ PHY specifier for the CVBS DAC
+
+ phy-names:
+ items:
+ - const: cvbs-dac
+
power-domains:
maxItems: 1
description: phandle to the associated power domain
@@ -130,6 +139,9 @@ examples:
#size-cells = <0>;
amlogic,canvas = <&canvas>;
+ phys = <&cvbs_dac_phy>;
+ phy-names = "cvbs-dac";
+
/* CVBS VDAC output port */
port@0 {
reg = <0>;
--
2.45.1

View File

@@ -0,0 +1,317 @@
From 8f9b70c8b353b2140e78d5aba6141b313d603e12 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 22:06:53 +0200
Subject: [PATCH 16/96] drm/meson: Add support for using a PHY for the CVBS DAC
Currently the VPU driver hardcodes the initialization, power-on and
power-off sequences for the CVBS DAC. The registers for the CVBS DAC are
in the HHI register area. Also the CVBS DAC is a PHY so it can be
modelled as such. Add support for using a PHY as CVBS DAC to de-couple
the VPU driver from the HHI registers (at least for this part of the
implementation).
Register a platform device for the PHY (which creates a lookup entry to
compensate for the missing .dtb entry) which takes over all
HHI_VDAC_CNTL register management.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/Kconfig | 1 +
drivers/gpu/drm/meson/meson_drv.h | 6 +
drivers/gpu/drm/meson/meson_encoder_cvbs.c | 132 ++++++++++++++++-----
drivers/gpu/drm/meson/meson_venc.c | 13 --
4 files changed, 110 insertions(+), 42 deletions(-)
diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
index 615fdd0ce..47e920105 100644
--- a/drivers/gpu/drm/meson/Kconfig
+++ b/drivers/gpu/drm/meson/Kconfig
@@ -10,6 +10,7 @@ config DRM_MESON
select REGMAP_MMIO
select MESON_CANVAS
select CEC_CORE if CEC_NOTIFIER
+ imply PHY_MESON_CVBS_DAC
config DRM_MESON_DW_HDMI
tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 3f9345c14..69be4c67f 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -16,6 +16,8 @@ struct drm_device;
struct drm_plane;
struct meson_drm;
struct meson_afbcd_ops;
+struct phy;
+struct platform_device;
enum vpu_compatible {
VPU_COMPATIBLE_GXBB = 0,
@@ -61,6 +63,10 @@ struct meson_drm {
const struct meson_drm_soc_limits *limits;
+ struct phy *cvbs_dac;
+ bool cvbs_dac_enabled;
+ struct platform_device *cvbs_dac_pdev;
+
/* Components Data */
struct {
bool osd1_enabled;
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index d1191de85..f849e0f85 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -11,6 +11,8 @@
#include <linux/export.h>
#include <linux/of_graph.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
@@ -24,12 +26,6 @@
#include "meson_vclk.h"
#include "meson_encoder_cvbs.h"
-/* HHI VDAC Registers */
-#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
-#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */
-#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
-#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */
-
struct meson_encoder_cvbs {
struct drm_encoder encoder;
struct drm_bridge bridge;
@@ -87,11 +83,28 @@ static int meson_encoder_cvbs_attach(struct drm_bridge *bridge,
{
struct meson_encoder_cvbs *meson_encoder_cvbs =
bridge_to_meson_encoder_cvbs(bridge);
+ int ret;
+
+ ret = phy_init(meson_encoder_cvbs->priv->cvbs_dac);
+ if (ret)
+ return ret;
return drm_bridge_attach(bridge->encoder, meson_encoder_cvbs->next_bridge,
&meson_encoder_cvbs->bridge, flags);
}
+static void meson_encoder_cvbs_detach(struct drm_bridge *bridge)
+{
+ struct meson_encoder_cvbs *meson_encoder_cvbs =
+ bridge_to_meson_encoder_cvbs(bridge);
+ int ret;
+
+ ret = phy_exit(meson_encoder_cvbs->priv->cvbs_dac);
+ if (ret)
+ dev_err(meson_encoder_cvbs->priv->dev,
+ "Failed to exit the CVBS DAC\n");
+}
+
static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
struct drm_connector *connector)
{
@@ -148,6 +161,7 @@ static void meson_encoder_cvbs_atomic_enable(struct drm_bridge *bridge,
struct drm_connector_state *conn_state;
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
+ int ret;
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
if (WARN_ON(!connector))
@@ -177,16 +191,13 @@ static void meson_encoder_cvbs_atomic_enable(struct drm_bridge *bridge,
writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0,
priv->io_base + _REG(VENC_VDAC_DACSEL0));
- if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
- } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
- meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
- } else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
+ if (!priv->cvbs_dac_enabled) {
+ ret = phy_power_on(priv->cvbs_dac);
+ if (ret)
+ dev_err(priv->dev,
+ "Failed to power on the CVBS DAC\n");
+ else
+ priv->cvbs_dac_enabled = true;
}
}
@@ -196,19 +207,22 @@ static void meson_encoder_cvbs_atomic_disable(struct drm_bridge *bridge,
struct meson_encoder_cvbs *meson_encoder_cvbs =
bridge_to_meson_encoder_cvbs(bridge);
struct meson_drm *priv = meson_encoder_cvbs->priv;
+ int ret;
- /* Disable CVBS VDAC */
- if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
- } else {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
- }
+ if (!priv->cvbs_dac_enabled)
+ return;
+
+ ret = phy_power_off(priv->cvbs_dac);
+ if (ret)
+ dev_err(priv->dev,
+ "Failed to power off the CVBS DAC\n");
+ else
+ priv->cvbs_dac_enabled = false;
}
static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
.attach = meson_encoder_cvbs_attach,
+ .detach = meson_encoder_cvbs_detach,
.mode_valid = meson_encoder_cvbs_mode_valid,
.get_modes = meson_encoder_cvbs_get_modes,
.atomic_enable = meson_encoder_cvbs_atomic_enable,
@@ -219,6 +233,54 @@ static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
.atomic_reset = drm_atomic_helper_bridge_reset,
};
+static int meson_cvbs_dac_probe(struct meson_drm *priv)
+{
+ struct platform_device *pdev;
+ const char *platform_id_name;
+
+ priv->cvbs_dac = devm_phy_optional_get(priv->dev, "cvbs-dac");
+ if (IS_ERR(priv->cvbs_dac))
+ return dev_err_probe(priv->dev, PTR_ERR(priv->cvbs_dac),
+ "Failed to get the 'cvbs-dac' PHY\n");
+ else if (priv->cvbs_dac)
+ return 0;
+
+ switch (priv->compat) {
+ case VPU_COMPATIBLE_GXBB:
+ platform_id_name = "meson-gxbb-cvbs-dac";
+ break;
+ case VPU_COMPATIBLE_GXL:
+ case VPU_COMPATIBLE_GXM:
+ platform_id_name = "meson-gxl-cvbs-dac";
+ break;
+ case VPU_COMPATIBLE_G12A:
+ platform_id_name = "meson-g12a-cvbs-dac";
+ break;
+ default:
+ return dev_err_probe(priv->dev, -EINVAL,
+ "No CVBS DAC platform ID found\n");
+ }
+
+ pdev = platform_device_register_data(priv->dev, platform_id_name,
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(pdev))
+ return dev_err_probe(priv->dev, PTR_ERR(pdev),
+ "Failed to register fallback CVBS DAC PHY platform device\n");
+
+ priv->cvbs_dac = platform_get_drvdata(pdev);
+ if (IS_ERR(priv->cvbs_dac)) {
+ platform_device_unregister(pdev);
+ return dev_err_probe(priv->dev, PTR_ERR(priv->cvbs_dac),
+ "Failed to get the 'cvbs-dac' PHY from it's platform device\n");
+ }
+
+ dev_info(priv->dev, "Using fallback for old .dtbs without CVBS DAC\n");
+
+ priv->cvbs_dac_pdev = pdev;
+
+ return 0;
+}
+
int meson_encoder_cvbs_probe(struct meson_drm *priv)
{
struct drm_device *drm = priv->drm;
@@ -255,6 +317,10 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
meson_encoder_cvbs->priv = priv;
+ ret = meson_cvbs_dac_probe(priv);
+ if (ret)
+ return ret;
+
/* Encoder */
ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
DRM_MODE_ENCODER_TVDAC);
@@ -268,21 +334,27 @@ int meson_encoder_cvbs_probe(struct meson_drm *priv)
ret = drm_bridge_attach(&meson_encoder_cvbs->encoder, &meson_encoder_cvbs->bridge, NULL,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret) {
- dev_err(priv->dev, "Failed to attach bridge: %d\n", ret);
- return ret;
+ dev_err_probe(priv->dev, ret, "Failed to attach bridge\n");
+ goto err_unregister_cvbs_dac_pdev;
}
/* Initialize & attach Bridge Connector */
connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
- if (IS_ERR(connector))
- return dev_err_probe(priv->dev, PTR_ERR(connector),
- "Unable to create CVBS bridge connector\n");
+ if (IS_ERR(connector)) {
+ ret = dev_err_probe(priv->dev, PTR_ERR(connector),
+ "Unable to create CVBS bridge connector\n");
+ goto err_unregister_cvbs_dac_pdev;
+ }
drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder);
priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs;
return 0;
+
+err_unregister_cvbs_dac_pdev:
+ platform_device_unregister(priv->cvbs_dac_pdev);
+ return ret;
}
void meson_encoder_cvbs_remove(struct meson_drm *priv)
@@ -293,4 +365,6 @@ void meson_encoder_cvbs_remove(struct meson_drm *priv)
meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS];
drm_bridge_remove(&meson_encoder_cvbs->bridge);
}
+
+ platform_device_unregister(priv->cvbs_dac_pdev);
}
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 3bf0d6e4f..5efd7a298 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -62,10 +62,6 @@
/* HHI Registers */
#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */
-#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
-#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbb offset in data sheet */
-#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
-#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbc offset in data sheet */
#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */
struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
@@ -1968,15 +1964,6 @@ void meson_venc_disable_vsync(struct meson_drm *priv)
void meson_venc_init(struct meson_drm *priv)
{
- /* Disable CVBS VDAC */
- if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8);
- } else {
- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
- }
-
/* Power Down Dacs */
writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
--
2.45.1

View File

@@ -0,0 +1,31 @@
From 182a6e3ae155fe2a0d9f4380c8f46b531d8e867b Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 May 2020 23:16:07 +0200
Subject: [PATCH 18/96] dt-bindings: clock: meson8b: Add the RMII reference
clock input
Amlogic Meson8 SoCs need an external 50MHz RMII reference clock. This is
either provided by the Ethernet PHY or an external oscillator. Add the
documentation for this clock input.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../devicetree/bindings/clock/amlogic,meson8b-clkc.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
index cc51e4746..a2602b5d5 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
+++ b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
@@ -16,6 +16,8 @@ Required Properties:
* "xtal": the 24MHz system oscillator
* "ddr_pll": the DDR PLL clock
* "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN)
+ * "rmii_clk": (if present) the 50MHz RMII reference clock (from the PHY or
+ an external oscillator
Parent node should have the following properties :
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
--
2.45.1

View File

@@ -0,0 +1,31 @@
From 2b1a5a4937e6de3aeba31fdd96946ff66d3c1608 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 May 2020 23:23:49 +0200
Subject: [PATCH 19/96] dt-bindings: clock: meson8b: Add the Meson8 Ethernet
(RMII) clocks
Export CLKID_ETH_CLK (and it's parents) because it is used as input for
the Ethernet controller on Meson8 SoCs.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
include/dt-bindings/clock/meson8b-clkc.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h
index 385bf243c..a09b686af 100644
--- a/include/dt-bindings/clock/meson8b-clkc.h
+++ b/include/dt-bindings/clock/meson8b-clkc.h
@@ -221,5 +221,9 @@
#define CLKID_VCLK2_EN 215
#define CLKID_VID_PLL_LVDS_EN 216
#define CLKID_HDMI_PLL_DCO_IN 217
+#define CLKID_ETH_CLK_SEL 218
+#define CLKID_ETH_CLK_DIV 219
+#define CLKID_ETH_CLK_PHASE 220
+#define CLKID_ETH_CLK 221
#endif /* __MESON8B_CLKC_H */
--
2.45.1

View File

@@ -0,0 +1,166 @@
From 1336f3b73beada616ef72126e736598e4503fbe0 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 May 2020 23:25:13 +0200
Subject: [PATCH 20/96] clk: meson: meson8b: Add the Ethernet (RMII) clock tree
on Meson8
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add the Ethernet clock tree on Meson8 which consists of:
- an input mux - the only known input is the RMII reference clock signal
which is an input on one of the SoC's pads
- a divider
- 0° or 180° phase change
- a gate to enable/disable the clock
Add these clocks only for Meson8 because they're only known to be used
there.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/clk/meson/Kconfig | 1 +
drivers/clk/meson/meson8b.c | 81 +++++++++++++++++++++++++++++++++++++
drivers/clk/meson/meson8b.h | 1 +
3 files changed, 83 insertions(+)
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 29ffd14d2..03e99ee3c 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -55,6 +55,7 @@ config COMMON_CLK_MESON8B
select COMMON_CLK_MESON_REGMAP
select COMMON_CLK_MESON_CLKC_UTILS
select COMMON_CLK_MESON_MPLL
+ select COMMON_CLK_MESON_PHASE
select COMMON_CLK_MESON_PLL
select MFD_SYSCON
select RESET_CONTROLLER
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index b7417ac26..8128e0864 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -19,6 +19,7 @@
#include "meson8b.h"
#include "clk-regmap.h"
#include "meson-clkc-utils.h"
+#include "clk-phase.h"
#include "clk-pll.h"
#include "clk-mpll.h"
@@ -2682,6 +2683,78 @@ static struct clk_regmap meson8b_cts_i958 = {
},
};
+static u32 meson8_eth_clk_mux_table[] = { 7 };
+
+static struct clk_regmap meson8_eth_clk_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = HHI_ETH_CLK_CNTL,
+ .mask = 0x7,
+ .shift = 9,
+ .table = meson8_eth_clk_mux_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "eth_clk_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ /* TODO: all other parents are unknown */
+ .fw_name = "rmii_clk",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap meson8_eth_clk_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = HHI_ETH_CLK_CNTL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "eth_clk_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &meson8_eth_clk_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap meson8_eth_clk_phase = {
+ .data = &(struct meson_clk_phase_data) {
+ .ph = {
+ .reg_off = HHI_ETH_CLK_CNTL,
+ .shift = 14,
+ .width = 1,
+ },
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "eth_clk_inverted",
+ .ops = &meson_clk_phase_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &meson8_eth_clk_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap meson8_eth_clk_gate = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = HHI_ETH_CLK_CNTL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "eth_clk_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &meson8_eth_clk_phase.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
#define MESON_GATE(_name, _reg, _bit) \
MESON_PCLK(_name, _reg, _bit, &meson8b_clk81.hw)
@@ -2978,6 +3051,10 @@ static struct clk_hw *meson8_hw_clks[] = {
[CLKID_CTS_I958] = &meson8b_cts_i958.hw,
[CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw,
[CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw,
+ [CLKID_ETH_CLK_SEL] = &meson8_eth_clk_sel.hw,
+ [CLKID_ETH_CLK_DIV] = &meson8_eth_clk_div.hw,
+ [CLKID_ETH_CLK_PHASE] = &meson8_eth_clk_phase.hw,
+ [CLKID_ETH_CLK] = &meson8_eth_clk_gate.hw,
};
static struct clk_hw *meson8b_hw_clks[] = {
@@ -3606,6 +3683,10 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8b_cts_mclk_i958,
&meson8b_cts_i958,
&meson8b_vid_pll_lvds_en,
+ &meson8_eth_clk_sel,
+ &meson8_eth_clk_div,
+ &meson8_eth_clk_phase,
+ &meson8_eth_clk_gate,
};
static const struct meson8b_clk_reset_line {
diff --git a/drivers/clk/meson/meson8b.h b/drivers/clk/meson/meson8b.h
index a5b6e67ee..dfec963d4 100644
--- a/drivers/clk/meson/meson8b.h
+++ b/drivers/clk/meson/meson8b.h
@@ -43,6 +43,7 @@
#define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in data sheet */
#define HHI_VPU_CLK_CNTL 0x1bc /* 0x6f offset in data sheet */
#define HHI_HDMI_CLK_CNTL 0x1cc /* 0x73 offset in data sheet */
+#define HHI_ETH_CLK_CNTL 0x1d8 /* 0x76 offset in data sheet */
#define HHI_VDEC_CLK_CNTL 0x1e0 /* 0x78 offset in data sheet */
#define HHI_VDEC2_CLK_CNTL 0x1e4 /* 0x79 offset in data sheet */
#define HHI_VDEC3_CLK_CNTL 0x1e8 /* 0x7a offset in data sheet */
--
2.45.1

View File

@@ -0,0 +1,52 @@
From a2f6824d3140baec1ba1b0748b0b3ee08f083185 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 May 2020 23:37:35 +0200
Subject: [PATCH 21/96] dt-bindings: net: dwmac-meson: Add the Ethernet clock
input for Meson6/8
The additional DWMAC register on Amlogic Meson6 and Meson8 SoCs take a
clock input (which is provided by the HHI clock controller). For RMII
mode this clock is derived from the RMII reference clock. Document this
clock input so the clock can be enabled when needed.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../bindings/net/amlogic,meson-dwmac.yaml | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml b/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml
index ee7a65b52..ea4b75ef6 100644
--- a/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/amlogic,meson-dwmac.yaml
@@ -127,6 +127,28 @@ allOf:
- 2800
- 3000
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - amlogic,meson6-dwmac
+ then:
+ properties:
+ clocks:
+ minItems: 1
+ maxItems: 2
+ items:
+ - description: GMAC main clock
+ - description: The RMII reference clock
+
+ clock-names:
+ minItems: 1
+ maxItems: 2
+ items:
+ - const: stmmaceth
+ - const: ethernet
+
properties:
compatible:
additionalItems: true
--
2.45.1

View File

@@ -0,0 +1,44 @@
From 237a072d8b71eecddce1f9ec7dda2ae7a46f27bf Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Dec 2021 04:07:05 +0100
Subject: [PATCH 22/96] net: stmmac: dwmac-meson: Rename the SPEED_100 macro
The SPEED_100 macro is part of the PREG_ETHERNET_ADDR0 register. Rename
it accordingly to make this relationship clear.
While here also add a comment what the SPEED_100 bit actually does.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index a16bfa908..919c41e15 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -15,7 +15,8 @@
#include "stmmac_platform.h"
-#define ETHMAC_SPEED_100 BIT(1)
+/* divides the input clock by 20 (= 0x0) or 2 (= 0x1) */
+#define PREG_ETHERNET_ADDR0_SPEED_100 BIT(1)
struct meson_dwmac {
struct device *dev;
@@ -31,10 +32,10 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned
switch (speed) {
case SPEED_10:
- val &= ~ETHMAC_SPEED_100;
+ val &= ~PREG_ETHERNET_ADDR0_SPEED_100;
break;
case SPEED_100:
- val |= ETHMAC_SPEED_100;
+ val |= PREG_ETHERNET_ADDR0_SPEED_100;
break;
}
--
2.45.1

View File

@@ -0,0 +1,117 @@
From 6cfa3555ebbfd9cfab319352f436ae9d7f0ffdea Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Dec 2021 04:22:53 +0100
Subject: [PATCH 23/96] net: stmmac: dwmac-meson: Manage the "ethernet" clock
Meson6 and Meson8 (both use the same glue registers on top of the DWMAC
IP) have a dedicated Ethernet clock. For RMII mode the SoC has an input
for an external RMII reference clock signal (which can be provided by
either the PHY or an external oscillator). This clock needs to run at
50MHz because the additional glue registers can divide by 2 - to achieve
25MHz for 100Mbit/s line speed, or 20 - to achieve 2.5MHz for 10Mbit/s
line speed.
Set the correct frequency for this clock and enable it during init. Also
enable the ETHMAC_DIV_EN bit which enables the divider in the glue
registers, based on the Ethernet clock input.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-meson.c | 51 ++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index 919c41e15..2361734e3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -5,6 +5,7 @@
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
*/
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/io.h>
@@ -15,12 +16,15 @@
#include "stmmac_platform.h"
+#define PREG_ETHERNET_ADDR0_DIV_EN BIT(0)
+
/* divides the input clock by 20 (= 0x0) or 2 (= 0x1) */
#define PREG_ETHERNET_ADDR0_SPEED_100 BIT(1)
struct meson_dwmac {
struct device *dev;
void __iomem *reg;
+ struct clk *ethernet_clk;
};
static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
@@ -42,6 +46,33 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned
writel(val, dwmac->reg);
}
+static int meson6_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct meson_dwmac *dwmac = priv;
+ int ret;
+
+ ret = clk_set_rate(dwmac->ethernet_clk, 50 * 1000 * 1000);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(dwmac->ethernet_clk);
+ if (ret)
+ return ret;
+
+ writel(readl(dwmac->reg) | PREG_ETHERNET_ADDR0_DIV_EN, dwmac->reg);
+
+ return 0;
+}
+
+static void meson6_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+ struct meson_dwmac *dwmac = priv;
+
+ writel(readl(dwmac->reg) & ~PREG_ETHERNET_ADDR0_DIV_EN, dwmac->reg);
+
+ clk_disable_unprepare(dwmac->ethernet_clk);
+}
+
static int meson6_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -65,10 +96,28 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
if (IS_ERR(dwmac->reg))
return PTR_ERR(dwmac->reg);
+ dwmac->ethernet_clk = devm_clk_get_optional(&pdev->dev, "ethernet");
+ if (IS_ERR(dwmac->ethernet_clk))
+ return PTR_ERR(dwmac->ethernet_clk);
+
plat_dat->bsp_priv = dwmac;
+ plat_dat->init = meson6_dwmac_init;
+ plat_dat->exit = meson6_dwmac_exit;
plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
- return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ ret = meson6_dwmac_init(pdev, dwmac);
+ if (ret)
+ return ret;
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ goto err_exit_dwmac;
+
+ return 0;
+
+err_exit_dwmac:
+ meson6_dwmac_exit(pdev, dwmac);
+ return ret;
}
static const struct of_device_id meson6_dwmac_match[] = {
--
2.45.1

View File

@@ -0,0 +1,76 @@
From 259fca64ab9ea66d43f6bd82584768fb0767789b Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Dec 2021 04:18:30 +0100
Subject: [PATCH 24/96] net: stmmac: dwmac-meson: Initialize all known
PREG_ETHERNET_ADDR0 bits
Initialize all known PREG_ETHERNET_ADDR0 register bits to be less
dependent on the bootloader to set them up correctly.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-meson.c | 25 ++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index 2361734e3..b96aa4d39 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -5,6 +5,7 @@
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/ethtool.h>
@@ -16,10 +17,20 @@
#include "stmmac_platform.h"
-#define PREG_ETHERNET_ADDR0_DIV_EN BIT(0)
+#define PREG_ETHERNET_ADDR0_DIV_EN BIT(0)
/* divides the input clock by 20 (= 0x0) or 2 (= 0x1) */
-#define PREG_ETHERNET_ADDR0_SPEED_100 BIT(1)
+#define PREG_ETHERNET_ADDR0_SPEED_100 BIT(1)
+
+/* 0x0 = little, 0x1 = big */
+#define PREG_ETHERNET_ADDR0_DATA_ENDIANNESS BIT(2)
+
+/* 0x0 = same order, 0x1: unknown */
+#define PREG_ETHERNET_ADDR0_DESC_ENDIANNESS BIT(3)
+
+#define PREG_ETHERNET_ADDR0_MII_MODE GENMASK(6, 4)
+#define PREG_ETHERNET_ADDR0_MII_MODE_RGMII 0x1
+#define PREG_ETHERNET_ADDR0_MII_MODE_RMII 0x4
struct meson_dwmac {
struct device *dev;
@@ -49,6 +60,7 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned
static int meson6_dwmac_init(struct platform_device *pdev, void *priv)
{
struct meson_dwmac *dwmac = priv;
+ u32 val;
int ret;
ret = clk_set_rate(dwmac->ethernet_clk, 50 * 1000 * 1000);
@@ -59,7 +71,14 @@ static int meson6_dwmac_init(struct platform_device *pdev, void *priv)
if (ret)
return ret;
- writel(readl(dwmac->reg) | PREG_ETHERNET_ADDR0_DIV_EN, dwmac->reg);
+ val = readl(dwmac->reg);
+ val &= ~PREG_ETHERNET_ADDR0_DATA_ENDIANNESS;
+ val &= ~PREG_ETHERNET_ADDR0_DESC_ENDIANNESS;
+ val &= ~PREG_ETHERNET_ADDR0_MII_MODE;
+ val |= FIELD_PREP(PREG_ETHERNET_ADDR0_MII_MODE,
+ PREG_ETHERNET_ADDR0_MII_MODE_RMII);
+ val |= PREG_ETHERNET_ADDR0_DIV_EN;
+ writel(val, dwmac->reg);
return 0;
}
--
2.45.1

View File

@@ -0,0 +1,34 @@
From e1e3ba72f71b31abadff7ce2443b3cdeafbdacf1 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 May 2020 23:47:47 +0200
Subject: [PATCH 25/96] ARM: dts: meson: meson8: Add the clock input to the
Ethernet controller
The Ethernet controller on Meson8 has an additional clock input from the
HHI clock controller. The clock signal provides the RMII reference clock
which is used to generate the internal 25MHz or 2.5MHz clocks depending
on the line speed.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index f57be9ae1..b2be52915 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -613,8 +613,8 @@ temperature_calib: calib@1f4 {
};
&ethmac {
- clocks = <&clkc CLKID_ETH>;
- clock-names = "stmmaceth";
+ clocks = <&clkc CLKID_ETH>, <&clkc CLKID_ETH_CLK>;
+ clock-names = "stmmaceth", "ethernet";
power-domains = <&pwrc PWRC_MESON8_ETHERNET_MEM_ID>;
};
--
2.45.1

View File

@@ -0,0 +1,30 @@
From 0361c56921d2f1c27f35bb5ef2165e5550a26d68 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 Jan 2021 19:01:08 +0100
Subject: [PATCH 26/96] dt-bindings: clock: meson8b: add the rtc_32k oscillator
input
The CLK81 tree can be driven off the 32kHz oscillator connected to the
SoCs RTC32K_XI and RTC32K_XO pads. Add this clock as a valid input.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../devicetree/bindings/clock/amlogic,meson8b-clkc.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
index a2602b5d5..855931509 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
+++ b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
@@ -18,6 +18,8 @@ Required Properties:
* "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN)
* "rmii_clk": (if present) the 50MHz RMII reference clock (from the PHY or
an external oscillator
+ * "rtc_32k": the clock signal from the 32kHz oscillator connected to the
+ RTC32K_XI and RTC32K_XO pads
Parent node should have the following properties :
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
--
2.45.1

View File

@@ -0,0 +1,108 @@
From 439df3198ef064825150418f9c1244a9f2a20aac Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 1 Jan 2021 18:55:05 +0100
Subject: [PATCH 27/96] clk: meson: meson8b: Add the mpeg_rtc_osc_sel clock
The first input of the CLK81 clock tree uses the SoC's external
oscillators. By default it's the 24MHz XTAL from which most frequencies
in this SoC are derived. For power-saving purposes there's a mux to
switch the input between the 24MHz XTAL and the 32kHz RTC oscillator.
Add support for that mux add it to the CLK81 clock tree for a better
representation of how the hardware is actually designed.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/clk/meson/meson8b.c | 26 ++++++++++++++++++++++--
include/dt-bindings/clock/meson8b-clkc.h | 1 +
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 8128e0864..2f7a2adda 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -611,7 +611,24 @@ static struct clk_regmap meson8b_mpll2 = {
},
};
-static u32 mux_table_clk81[] = { 6, 5, 7 };
+static struct clk_regmap meson8b_mpeg_rtc_osc_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_MPEG_CLK_CNTL,
+ .mask = 0x1,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mpeg_rtc_osc_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_data = (const struct clk_parent_data[]) {
+ { .fw_name = "xtal", .index = -1, },
+ { .fw_name = "rtc_32k", .index = -1, },
+ },
+ .num_parents = 2,
+ },
+};
+
+static u32 mux_table_clk81[] = { 0, 6, 5, 7 };
static struct clk_regmap meson8b_mpeg_clk_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_MPEG_CLK_CNTL,
@@ -628,11 +645,12 @@ static struct clk_regmap meson8b_mpeg_clk_sel = {
* fclk_div4, fclk_div3, fclk_div5
*/
.parent_hws = (const struct clk_hw *[]) {
+ &meson8b_mpeg_rtc_osc_sel.hw,
&meson8b_fclk_div3.hw,
&meson8b_fclk_div4.hw,
&meson8b_fclk_div5.hw,
},
- .num_parents = 3,
+ .num_parents = 4,
},
};
@@ -3055,6 +3073,7 @@ static struct clk_hw *meson8_hw_clks[] = {
[CLKID_ETH_CLK_DIV] = &meson8_eth_clk_div.hw,
[CLKID_ETH_CLK_PHASE] = &meson8_eth_clk_phase.hw,
[CLKID_ETH_CLK] = &meson8_eth_clk_gate.hw,
+ [CLKID_MPEG_RTC_OSC_SEL] = &meson8b_mpeg_rtc_osc_sel.hw,
};
static struct clk_hw *meson8b_hw_clks[] = {
@@ -3270,6 +3289,7 @@ static struct clk_hw *meson8b_hw_clks[] = {
[CLKID_CTS_I958] = &meson8b_cts_i958.hw,
[CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw,
[CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw,
+ [CLKID_MPEG_RTC_OSC_SEL] = &meson8b_mpeg_rtc_osc_sel.hw,
};
static struct clk_hw *meson8m2_hw_clks[] = {
@@ -3487,6 +3507,7 @@ static struct clk_hw *meson8m2_hw_clks[] = {
[CLKID_CTS_I958] = &meson8b_cts_i958.hw,
[CLKID_VID_PLL_LVDS_EN] = &meson8b_vid_pll_lvds_en.hw,
[CLKID_HDMI_PLL_DCO_IN] = &hdmi_pll_dco_in.hw,
+ [CLKID_MPEG_RTC_OSC_SEL] = &meson8b_mpeg_rtc_osc_sel.hw,
};
static struct clk_regmap *const meson8b_clk_regmaps[] = {
@@ -3687,6 +3708,7 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
&meson8_eth_clk_div,
&meson8_eth_clk_phase,
&meson8_eth_clk_gate,
+ &meson8b_mpeg_rtc_osc_sel,
};
static const struct meson8b_clk_reset_line {
diff --git a/include/dt-bindings/clock/meson8b-clkc.h b/include/dt-bindings/clock/meson8b-clkc.h
index a09b686af..fe6c02e04 100644
--- a/include/dt-bindings/clock/meson8b-clkc.h
+++ b/include/dt-bindings/clock/meson8b-clkc.h
@@ -225,5 +225,6 @@
#define CLKID_ETH_CLK_DIV 219
#define CLKID_ETH_CLK_PHASE 220
#define CLKID_ETH_CLK 221
+#define CLKID_MPEG_RTC_OSC_SEL 222
#endif /* __MESON8B_CLKC_H */
--
2.45.1

View File

@@ -0,0 +1,85 @@
From b9f75c5b68a79dee3c4ca723a4ee92521118a92d Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 28 Aug 2021 18:50:10 +0200
Subject: [PATCH 28/96] ARM: dts: meson: Add #address-cells, #size-cells and
ranges to hhi
The HHI node has multiple child-nodes. Add #address-cells, #size-cells
and ranges properties to the hhi node itself so the child-nodes can get
their own offset and register sizes. Also add the reg property to the
clock and power domain controllers inside the hhi region.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson.dtsi | 3 +++
arch/arm/boot/dts/amlogic/meson8.dtsi | 6 ++++--
arch/arm/boot/dts/amlogic/meson8b.dtsi | 6 ++++--
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/amlogic/meson.dtsi b/arch/arm/boot/dts/amlogic/meson.dtsi
index 0e7756c95..d7f50fec8 100644
--- a/arch/arm/boot/dts/amlogic/meson.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson.dtsi
@@ -35,6 +35,9 @@ hhi: system-controller@4000 {
"simple-mfd",
"syscon";
reg = <0x4000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x4000 0x400>;
};
aiu: audio-controller@5400 {
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index b2be52915..d925bdcc0 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -625,16 +625,18 @@ &gpio_intc {
};
&hhi {
- clkc: clock-controller {
+ clkc: clock-controller@0 {
compatible = "amlogic,meson8-clkc";
+ reg = <0x0 0x39c>;
clocks = <&xtal>, <&ddr_clkc DDR_CLKID_DDR_PLL>;
clock-names = "xtal", "ddr_pll";
#clock-cells = <1>;
#reset-cells = <1>;
};
- pwrc: power-controller {
+ pwrc: power-controller@100 {
compatible = "amlogic,meson8-pwrc";
+ reg = <0x100 0x10>;
#power-domain-cells = <1>;
amlogic,ao-sysctrl = <&pmu>;
clocks = <&clkc CLKID_VPU>;
diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi
index 2d9d24d3a..5ffedca99 100644
--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi
@@ -586,16 +586,18 @@ &gpio_intc {
};
&hhi {
- clkc: clock-controller {
+ clkc: clock-controller@0 {
compatible = "amlogic,meson8b-clkc";
+ reg = <0x0 0x39c>;
clocks = <&xtal>, <&ddr_clkc DDR_CLKID_DDR_PLL>;
clock-names = "xtal", "ddr_pll";
#clock-cells = <1>;
#reset-cells = <1>;
};
- pwrc: power-controller {
+ pwrc: power-controller@100 {
compatible = "amlogic,meson8b-pwrc";
+ reg = <0x100 0x10>;
#power-domain-cells = <1>;
amlogic,ao-sysctrl = <&pmu>;
resets = <&reset RESET_DBLK>,
--
2.45.1

View File

@@ -0,0 +1,77 @@
From 5e640e96e1224868456fda4cc2c9e8cca273a79c Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 17 May 2021 22:50:25 +0200
Subject: [PATCH 29/96] dt-bindings: firmware: Document the Amlogic
Meson6/8/8b/8m2 TrustZone
Amlogic Meson6/8/8b/8m2 SoCs can optionally use a TrustZone secure
firmware. This prevents anything outside of the TEE (Trusted
Execution Environment aka TrustZone secure firmware) from accessing
certain functionality of these SoCs, such as (but not limited to):
Bringing up/down secondary SMP cores, accessing the eFuse and getting
the SoC misc version.
ARM SMCCC is used for communication with the TrustZone secure
firmware.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../amlogic,meson-mx-trustzone-firmware.yaml | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 Documentation/devicetree/bindings/firmware/meson/amlogic,meson-mx-trustzone-firmware.yaml
diff --git a/Documentation/devicetree/bindings/firmware/meson/amlogic,meson-mx-trustzone-firmware.yaml b/Documentation/devicetree/bindings/firmware/meson/amlogic,meson-mx-trustzone-firmware.yaml
new file mode 100644
index 000000000..1e0e19a35
--- /dev/null
+++ b/Documentation/devicetree/bindings/firmware/meson/amlogic,meson-mx-trustzone-firmware.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/firmware/meson/amlogic,meson-mx-trustzone-firmware.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Meson6/8/8b/8m2 TrustZone secure firmware
+
+description: |
+ Amlogic Meson6/8/8b/8m2 SoCs can optionally use a TrustZone secure
+ firmware. This prevents anything outside of the TEE (Trusted
+ Execution Environment aka TrustZone secure firmware) from accessing
+ certain functionality of these SoCs, such as (but not limited to):
+ Bringing up/down secondary SMP cores, accessing the eFuse and getting
+ the SoC misc version.
+ ARM SMCCC is used for communication with the TrustZone secure
+ firmware.
+
+maintainers:
+ - Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - amlogic,meson6-trustzone-firmware
+ - amlogic,meson8-trustzone-firmware
+ - amlogic,meson8b-trustzone-firmware
+ - amlogic,meson8m2-trustzone-firmware
+ - const: amlogic,meson-mx-trustzone-firmware
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ firmware {
+ trustzone-firmware {
+ compatible = "amlogic,meson8m2-trustzone-firmware",
+ "amlogic,meson-mx-trustzone-firmware";
+ };
+ };
+...
--
2.45.1

View File

@@ -0,0 +1,31 @@
From f753ee1373a56cee5d6c2e7c107a85822828c983 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 18 Dec 2021 16:38:16 +0100
Subject: [PATCH 30/96] dt-bindings: arm: cpus: Document Meson8 TrustZone
firmware enable-method
Amlogic Meson8 SoCs can run a TrustZone firmware. This results in the
CPU registers not being accessible directly and instead require firmware
calls for booting the secondary cores or powering off a CPU. Add a new
compatible string for this enable-method.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
Documentation/devicetree/bindings/arm/cpus.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml
index cc5a21b47..ec7593e04 100644
--- a/Documentation/devicetree/bindings/arm/cpus.yaml
+++ b/Documentation/devicetree/bindings/arm/cpus.yaml
@@ -216,6 +216,7 @@ properties:
- allwinner,sun9i-a80-smp
- allwinner,sun8i-a83t-smp
- amlogic,meson8-smp
+ - amlogic,meson8-trustzone-firmware-smp
- amlogic,meson8b-smp
- arm,realview-smp
- aspeed,ast2600-smp
--
2.45.1

View File

@@ -0,0 +1,439 @@
From 5499854ac2d2227951eb9e0437a5897d038cca97 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 3 May 2021 00:34:53 +0200
Subject: [PATCH 31/96] ARM: meson: Add support for the TrustZone firmware
Amlogic Meson6/8/8b/8m2 SoCs can optionally use a TrustZone secure
firmware. This prevents anything outside of the TEE (Trusted
Execution Environment aka TrustZone secure firmware) from accessing
certain functionality of these SoCs, such as (but not limited to):
Bringing up/down secondary SMP cores, accessing the eFuse and getting
the SoC misc version.
ARM SMCCC is used for communication with the TrustZone secure
firmware.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/mach-meson/Makefile | 2 +-
arch/arm/mach-meson/meson.c | 4 +
arch/arm/mach-meson/tz_firmware.c | 250 ++++++++++++++++++
arch/arm/mach-meson/tz_firmware.h | 76 ++++++
.../linux/firmware/meson/meson_mx_trustzone.h | 37 +++
5 files changed, 368 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/mach-meson/tz_firmware.c
create mode 100644 arch/arm/mach-meson/tz_firmware.h
create mode 100644 include/linux/firmware/meson/meson_mx_trustzone.h
diff --git a/arch/arm/mach-meson/Makefile b/arch/arm/mach-meson/Makefile
index 49cfbaee4..b8fe5f140 100644
--- a/arch/arm/mach-meson/Makefile
+++ b/arch/arm/mach-meson/Makefile
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ARCH_MESON) += meson.o
+obj-$(CONFIG_ARCH_MESON) += meson.o tz_firmware.o
obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-meson/meson.c b/arch/arm/mach-meson/meson.c
index d3ae89dd8..45dae29a4 100644
--- a/arch/arm/mach-meson/meson.c
+++ b/arch/arm/mach-meson/meson.c
@@ -5,6 +5,8 @@
#include <asm/mach/arch.h>
+#include "tz_firmware.h"
+
static const char * const meson_common_board_compat[] = {
"amlogic,meson6",
"amlogic,meson8",
@@ -17,4 +19,6 @@ DT_MACHINE_START(MESON, "Amlogic Meson platform")
.dt_compat = meson_common_board_compat,
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
+ .init_early = meson_mx_trustzone_firmware_init,
+ .reserve = meson_mx_trustzone_firmware_reserve_mem,
MACHINE_END
diff --git a/arch/arm/mach-meson/tz_firmware.c b/arch/arm/mach-meson/tz_firmware.c
new file mode 100644
index 000000000..9cdad4144
--- /dev/null
+++ b/arch/arm/mach-meson/tz_firmware.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/firmware/meson/meson_mx_trustzone.h>
+#include <linux/memblock.h>
+#include <linux/of.h>
+
+#include <asm/firmware.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/outercache.h>
+
+#include "tz_firmware.h"
+
+struct meson_mx_trustzone_firmware_memconfig {
+ unsigned char name[64];
+ unsigned int start_phy_addr;
+ unsigned int end_phy_addr;
+} __packed;
+
+static struct meson_mx_trustzone_firmware_memconfig meson_firmware_memconfig[2];
+
+static int meson_mx_trustzone_firmware_hal_api(unsigned int cmd, u32 *args)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(MESON_CALL_TRUSTZONE_HAL_API, cmd, virt_to_phys(args), 0,
+ 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static u32 meson_mx_trustzone_firmware_mon(unsigned int cmd, unsigned int arg0,
+ unsigned int arg1)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(MESON_CALL_TRUSTZONE_MON, cmd, arg0, arg1, 0, 0, 0, 0,
+ &res);
+
+ return res.a0;
+}
+
+static int meson_mx_trustzone_firmware_set_cpu_boot_addr(int cpu,
+ unsigned long boot_addr){
+ return meson_mx_trustzone_firmware_mon(MESON_TRUSTZONE_MON_CORE_BOOTADDR_INDEX,
+ cpu, boot_addr);
+}
+
+static int meson_mx_trustzone_firmware_cpu_boot(int cpu)
+{
+ u32 ret, corectrl;
+
+ corectrl = meson_mx_trustzone_firmware_mon(MESON_TRUSTZONE_MON_CORE_RD_CTRL_INDEX,
+ 0, 0);
+
+ corectrl |= BIT(cpu);
+
+ ret = meson_mx_trustzone_firmware_mon(MESON_TRUSTZONE_MON_CORE_WR_CTRL_INDEX,
+ corectrl, 0);
+ if (ret != corectrl)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void meson_mx_trustzone_firmware_l2x0_write_sec(unsigned long val,
+ unsigned int reg)
+{
+ u32 fn;
+
+ switch (reg) {
+ case L2X0_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_CTRL_INDEX;
+ break;
+
+ case L2X0_AUX_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_AUXCTRL_INDEX;
+ break;
+
+ case L310_TAG_LATENCY_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_TAGLATENCY_INDEX;
+ break;
+
+ case L310_DATA_LATENCY_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_DATALATENCY_INDEX;
+ break;
+
+ case L310_ADDR_FILTER_START:
+ fn = MESON_TRUSTZONE_MON_L2X0_FILTERSTART_INDEX;
+ break;
+
+ case L310_ADDR_FILTER_END:
+ fn = MESON_TRUSTZONE_MON_L2X0_FILTEREND_INDEX;
+ break;
+
+ case L2X0_DEBUG_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_DEBUG_INDEX;
+ break;
+
+ case L310_PREFETCH_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_PREFETCH_INDEX;
+ break;
+
+ case L310_POWER_CTRL:
+ fn = MESON_TRUSTZONE_MON_L2X0_POWER_INDEX;
+ break;
+
+ default:
+ pr_warn("Amlogic Meson TrustZone - unsupported L2X0 register 0x%08x\n",
+ reg);
+ return;
+ }
+
+ WARN_ON(meson_mx_trustzone_firmware_mon(fn, val, 0));
+}
+
+static int __maybe_unused meson_mx_trustzone_firmware_l2x0_init(void)
+{
+ if (IS_ENABLED(CONFIG_CACHE_L2X0))
+ outer_cache.write_sec = meson_mx_trustzone_firmware_l2x0_write_sec;
+
+ return 0;
+}
+
+static const struct firmware_ops meson_mx_trustzone_firmware_ops = {
+ .set_cpu_boot_addr = meson_mx_trustzone_firmware_set_cpu_boot_addr,
+ .cpu_boot = meson_mx_trustzone_firmware_cpu_boot,
+ .l2x0_init = meson_mx_trustzone_firmware_l2x0_init,
+};
+
+void __init meson_mx_trustzone_firmware_init(void)
+{
+ if (!meson_mx_trustzone_firmware_available())
+ return;
+
+ pr_info("Running under Amlogic Meson TrustZone secure firmware.\n");
+
+ register_firmware_ops(&meson_mx_trustzone_firmware_ops);
+
+ call_firmware_op(l2x0_init);
+}
+
+static void __init meson_mx_trustzone_firmware_memconfig_init(void)
+{
+ unsigned int i, size;
+ u32 args[2] = {
+ __pa_symbol(meson_firmware_memconfig),
+ ARRAY_SIZE(meson_firmware_memconfig),
+ };
+ int ret;
+
+ ret = meson_mx_trustzone_firmware_hal_api(MESON_TRUSTZONE_HAL_API_MEMCONFIG,
+ args);
+ if (ret) {
+ pr_err("Amlogic Meson TrustZone memconfig failed: %d\n", ret);
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(meson_firmware_memconfig); i++) {
+ size = meson_firmware_memconfig[i].end_phy_addr -
+ meson_firmware_memconfig[i].start_phy_addr;
+
+ pr_debug("\tAmlogic Meson TrustZone memblock[%d]: %s (%u bytes)\n",
+ i, meson_firmware_memconfig[i].name, size);
+
+ ret = memblock_mark_nomap(meson_firmware_memconfig[i].start_phy_addr,
+ size);
+ if (ret)
+ pr_err("Failed to reserve %u bytes for Amlogic Meson TrustZone memblock[%d] (%s): %d\n",
+ size, i, meson_firmware_memconfig[i].name, ret);
+ }
+}
+
+static void __init meson_mx_trustzone_firmware_monitor_memory_init(void)
+{
+ u32 base, size;
+ int ret;
+
+ base = meson_mx_trustzone_firmware_mon(MESON_TRUSTZONE_MON_MEM_BASE,
+ 0, 0);
+ WARN_ON(!base);
+
+ size = meson_mx_trustzone_firmware_mon(MESON_TRUSTZONE_MON_MEM_TOTAL_SIZE,
+ 0, 0);
+ WARN_ON(!size);
+
+ ret = memblock_mark_nomap(base, size);
+ if (ret)
+ pr_err("Failed to reserve %u bytes of Amlogic Meson TrustZone monitor memory: %d\n",
+ size, ret);
+}
+
+void __init meson_mx_trustzone_firmware_reserve_mem(void)
+{
+ if (!meson_mx_trustzone_firmware_available())
+ return;
+
+ meson_mx_trustzone_firmware_monitor_memory_init();
+ meson_mx_trustzone_firmware_memconfig_init();
+}
+
+bool meson_mx_trustzone_firmware_available(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL,
+ "amlogic,meson-mx-trustzone-firmware");
+ if (!np)
+ return false;
+
+ of_node_put(np);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(meson_mx_trustzone_firmware_available);
+
+int meson_mx_trustzone_firmware_efuse_read(unsigned int offset,
+ unsigned int bytes, void *buf)
+{
+ unsigned int read_bytes;
+ u32 args[5] = {
+ MESON_TRUSTZONE_HAL_API_EFUSE_CMD_READ,
+ offset,
+ bytes,
+ __pa_symbol(buf),
+ virt_to_phys(&read_bytes)
+ };
+ int ret;
+
+ ret = meson_mx_trustzone_firmware_hal_api(MESON_TRUSTZONE_HAL_API_EFUSE,
+ args);
+ if (ret)
+ return -EIO;
+
+ if (read_bytes != bytes)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(meson_mx_trustzone_firmware_efuse_read);
+
+u32 meson_mx_trustzone_read_soc_rev1(void)
+{
+ return meson_mx_trustzone_firmware_mon(MESON_TRUSTZONE_MON_CORE_RD_SOC_REV1,
+ 0, 0);
+}
+EXPORT_SYMBOL_GPL(meson_mx_trustzone_read_soc_rev1);
diff --git a/arch/arm/mach-meson/tz_firmware.h b/arch/arm/mach-meson/tz_firmware.h
new file mode 100644
index 000000000..a9da3c84a
--- /dev/null
+++ b/arch/arm/mach-meson/tz_firmware.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Amlogic Meson6/8/8b/8m2 secure TrustZone firmware definitions.
+ *
+ * Based on meson-secure.c and meson-secure.h from the Amlogic vendor kernel:
+ * Copyright (C) 2002 ARM Ltd.
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2013 Amlogic, Inc.
+ * Author: Platform-SH@amlogic.com
+ *
+ * Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+/* Meson Secure Monitor/HAL APIs */
+#define MESON_CALL_TRUSTZONE_API 0x1
+#define MESON_CALL_TRUSTZONE_MON 0x4
+#define MESON_CALL_TRUSTZONE_HAL_API 0x5
+
+/* Secure Monitor mode APIs */
+#define MESON_TRUSTZONE_MON_TYPE_MASK 0xF00
+#define MESON_TRUSTZONE_MON_FUNC_MASK 0x0FF
+
+#define MESON_TRUSTZONE_MON_L2X0 0x100
+#define MESON_TRUSTZONE_MON_L2X0_CTRL_INDEX 0x101
+#define MESON_TRUSTZONE_MON_L2X0_AUXCTRL_INDEX 0x102
+#define MESON_TRUSTZONE_MON_L2X0_PREFETCH_INDEX 0x103
+#define MESON_TRUSTZONE_MON_L2X0_TAGLATENCY_INDEX 0x104
+#define MESON_TRUSTZONE_MON_L2X0_DATALATENCY_INDEX 0x105
+#define MESON_TRUSTZONE_MON_L2X0_FILTERSTART_INDEX 0x106
+#define MESON_TRUSTZONE_MON_L2X0_FILTEREND_INDEX 0x107
+#define MESON_TRUSTZONE_MON_L2X0_DEBUG_INDEX 0x108
+#define MESON_TRUSTZONE_MON_L2X0_POWER_INDEX 0x109
+
+#define MESON_TRUSTZONE_MON_CORE 0x200
+#define MESON_TRUSTZONE_MON_CORE_RD_CTRL_INDEX 0x201
+#define MESON_TRUSTZONE_MON_CORE_WR_CTRL_INDEX 0x202
+#define MESON_TRUSTZONE_MON_CORE_RD_STATUS0_INDEX 0x203
+#define MESON_TRUSTZONE_MON_CORE_WR_STATUS0_INDEX 0x204
+#define MESON_TRUSTZONE_MON_CORE_RD_STATUS1_INDEX 0x205
+#define MESON_TRUSTZONE_MON_CORE_WR_STATUS1_INDEX 0x206
+#define MESON_TRUSTZONE_MON_CORE_BOOTADDR_INDEX 0x207
+#define MESON_TRUSTZONE_MON_CORE_DDR_INDEX 0x208
+#define MESON_TRUSTZONE_MON_CORE_RD_SOC_REV1 0x209
+#define MESON_TRUSTZONE_MON_CORE_RD_SOC_REV2 0x20A
+
+#define MESON_TRUSTZONE_MON_SUSPEND_FIRMWARE 0x300
+#define MESON_TRUSTZONE_MON_SAVE_CPU_GIC 0x400
+
+#define MESON_TRUSTZONE_MON_RTC 0x500
+#define MESON_TRUSTZONE_MON_RTC_RD_REG_INDEX 0x501
+#define MESON_TRUSTZONE_MON_RTC_WR_REG_INDEX 0x502
+
+#define MESON_TRUSTZONE_MON_REG 0x600
+#define MESON_TRUSTZONE_MON_REG_RD_INDEX 0x601
+#define MESON_TRUSTZONE_MON_REG_WR_INDEX 0x602
+
+#define MESON_TRUSTZONE_MON_MEM 0x700
+#define MESON_TRUSTZONE_MON_MEM_BASE 0x701
+#define MESON_TRUSTZONE_MON_MEM_TOTAL_SIZE 0x702
+#define MESON_TRUSTZONE_MON_MEM_FLASH 0x703
+#define MESON_TRUSTZONE_MON_MEM_FLASH_SIZE 0x704
+#define MESON_TRUSTZONE_MON_MEM_GE2D 0x705
+
+/* Secure HAL APIs*/
+#define MESON_TRUSTZONE_HAL_API_EFUSE 0x100
+#define MESON_TRUSTZONE_HAL_API_EFUSE_CMD_READ 0x0
+#define MESON_TRUSTZONE_HAL_API_EFUSE_CMD_WRITE 0x1
+#define MESON_TRUSTZONE_HAL_API_EFUSE_CMD_VERIFY_IMG 0x3
+
+#define MESON_TRUSTZONE_HAL_API_STORAGE 0x200
+
+#define MESON_TRUSTZONE_HAL_API_MEMCONFIG 0x300
+#define MESON_TRUSTZONE_HAL_API_MEMCONFIG_GE2D 0x301
+
+void __init meson_mx_trustzone_firmware_init(void);
+void __init meson_mx_trustzone_firmware_reserve_mem(void);
diff --git a/include/linux/firmware/meson/meson_mx_trustzone.h b/include/linux/firmware/meson/meson_mx_trustzone.h
new file mode 100644
index 000000000..947463050
--- /dev/null
+++ b/include/linux/firmware/meson/meson_mx_trustzone.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_MESON)
+
+bool meson_mx_trustzone_firmware_available(void);
+
+int meson_mx_trustzone_firmware_efuse_read(unsigned int offset,
+ unsigned int bytes, void *buf);
+
+u32 meson_mx_trustzone_read_soc_rev1(void);
+
+#else
+
+static inline bool meson_mx_trustzone_firmware_available(void)
+{
+ return false;
+}
+
+static inline int meson_mx_trustzone_firmware_efuse_read(unsigned int offset,
+ unsigned int bytes,
+ void *buf)
+{
+ return -EINVAL;
+}
+
+static inline u32 meson_mx_trustzone_read_soc_rev1(void)
+{
+ return 0;
+}
+
+#endif
--
2.45.1

View File

@@ -0,0 +1,75 @@
From 342867fae2835ccac6edc355c6d115f9e69a4eeb Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 3 May 2021 08:36:16 +0200
Subject: [PATCH 32/96] ARM: meson: platsmp: Add support for SoCs running on
TrustZone firmware
When the SoC is running on the TrustZone firmware we cannot modify the
SMP related registers. Add a new set of SMP ops which use firmware calls
to set the startup (function) address and core control (on/off).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/mach-meson/platsmp.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm/mach-meson/platsmp.c b/arch/arm/mach-meson/platsmp.c
index 32ac60b89..3e38066fc 100644
--- a/arch/arm/mach-meson/platsmp.c
+++ b/arch/arm/mach-meson/platsmp.c
@@ -16,6 +16,7 @@
#include <asm/cacheflush.h>
#include <asm/cp15.h>
+#include <asm/firmware.h>
#include <asm/smp_scu.h>
#include <asm/smp_plat.h>
@@ -291,6 +292,31 @@ static int meson8b_smp_boot_secondary(unsigned int cpu,
return 0;
}
+static int meson8_smp_trustzone_firmware_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ unsigned int addr = __pa_symbol(secondary_startup);
+ int ret;
+
+ ret = call_firmware_op(set_cpu_boot_addr, cpu, addr);
+ if (ret) {
+ pr_err("Failed to set aux core boot address for CPU%u using TrustZone secure firmware\n",
+ cpu);
+ return ret;
+ }
+
+ ret = call_firmware_op(cpu_boot, cpu);
+ if (ret) {
+ pr_err("Failed to modify core control for CPU%u using TrustZone secure firmware\n",
+ cpu);
+ return ret;
+ }
+
+ udelay(10);
+
+ return 0;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
static void meson8_smp_cpu_die(unsigned int cpu)
{
@@ -428,5 +454,12 @@ static struct smp_operations meson8b_smp_ops __initdata = {
#endif
};
+static struct smp_operations meson8_smp_trustzone_firmware_ops __initdata = {
+ .smp_boot_secondary = meson8_smp_trustzone_firmware_boot_secondary,
+};
+
CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,meson8-smp", &meson8_smp_ops);
CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,meson8b-smp", &meson8b_smp_ops);
+CPU_METHOD_OF_DECLARE(meson8_trustzone_firmware_smp,
+ "amlogic,meson8-trustzone-firmware-smp",
+ &meson8_smp_trustzone_firmware_ops);
--
2.45.1

View File

@@ -0,0 +1,68 @@
From 77011250fbd490a4b85363f62e7c4e639191a4ec Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 16 May 2021 19:48:54 +0200
Subject: [PATCH 33/96] soc: amlogic: meson-mx-socinfo: Add support for the
TrustZone firmware
When the TrustZone firmware is enabled the SoC is configured so the boot
ROM cannot be read from the (untrusted) Linux kernel. Instead a firmware
call needs to be used to get the SoC's "misc" version.
Add support for the firmware call to retrieve the SoC's misc version if
the TrustZone firmware is loaded.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/soc/amlogic/meson-mx-socinfo.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/amlogic/meson-mx-socinfo.c b/drivers/soc/amlogic/meson-mx-socinfo.c
index 92125dd65..25503bdd7 100644
--- a/drivers/soc/amlogic/meson-mx-socinfo.c
+++ b/drivers/soc/amlogic/meson-mx-socinfo.c
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <linux/firmware/meson/meson_mx_trustzone.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -118,10 +119,12 @@ static int __init meson_mx_socinfo_init(void)
if (IS_ERR(assist_regmap))
return PTR_ERR(assist_regmap);
- bootrom_regmap =
- syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom");
- if (IS_ERR(bootrom_regmap))
- return PTR_ERR(bootrom_regmap);
+ if (!meson_mx_trustzone_firmware_available()) {
+ bootrom_regmap =
+ syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom");
+ if (IS_ERR(bootrom_regmap))
+ return PTR_ERR(bootrom_regmap);
+ }
np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
if (np) {
@@ -141,10 +144,14 @@ static int __init meson_mx_socinfo_init(void)
if (ret < 0)
return ret;
- ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER,
- &misc_ver);
- if (ret < 0)
- return ret;
+ if (meson_mx_trustzone_firmware_available()) {
+ misc_ver = meson_mx_trustzone_read_soc_rev1();
+ } else {
+ ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER,
+ &misc_ver);
+ if (ret < 0)
+ return ret;
+ }
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
--
2.45.1

View File

@@ -0,0 +1,73 @@
From a6e38e2f0cc7be7d75ed8b9895e7bc7af99d0fe0 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 3 May 2021 00:35:22 +0200
Subject: [PATCH 34/96] nvmem: meson-mx-efuse: Add support for the TrustZone
firmware interface
Some boards have a TrustZone firmware which prevents us from accessing
(most of) the eFuse registers. On these boards we must use read the
eFuse through TrustZone firmware calls (using SMC).
Implement a .reg_read op using the Meson TrustZone firmware interface.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/nvmem/meson-mx-efuse.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/meson-mx-efuse.c b/drivers/nvmem/meson-mx-efuse.c
index 3ff04d5ca..1a08f5541 100644
--- a/drivers/nvmem/meson-mx-efuse.c
+++ b/drivers/nvmem/meson-mx-efuse.c
@@ -9,6 +9,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/firmware/meson/meson_mx_trustzone.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@@ -166,6 +167,28 @@ static int meson_mx_efuse_read(void *context, unsigned int offset,
return err;
}
+static int meson_mx_efuse_read_trustzone_firmware(void *context,
+ unsigned int offset,
+ void *buf, size_t bytes)
+{
+ struct meson_mx_efuse *efuse = context;
+ unsigned int tmp;
+ int i, ret;
+
+ for (i = 0; i < bytes; i += efuse->config.word_size) {
+ ret = meson_mx_trustzone_firmware_efuse_read(offset + i,
+ sizeof(tmp),
+ &tmp);
+ if (ret)
+ return ret;
+
+ memcpy(buf + i, &tmp,
+ min_t(size_t, bytes - i, efuse->config.word_size));
+ }
+
+ return 0;
+}
+
static const struct meson_mx_efuse_platform_data meson6_efuse_data = {
.name = "meson6-efuse",
.word_size = 1,
@@ -215,7 +238,11 @@ static int meson_mx_efuse_probe(struct platform_device *pdev)
efuse->config.word_size = drvdata->word_size;
efuse->config.size = SZ_512;
efuse->config.read_only = true;
- efuse->config.reg_read = meson_mx_efuse_read;
+
+ if (meson_mx_trustzone_firmware_available())
+ efuse->config.reg_read = meson_mx_efuse_read_trustzone_firmware;
+ else
+ efuse->config.reg_read = meson_mx_efuse_read;
efuse->core_clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(efuse->core_clk)) {
--
2.45.1

View File

@@ -0,0 +1,45 @@
From 77298a6b2e7937abfefb0514469b03c223cb6414 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Thu, 22 Jul 2021 08:27:29 +0200
Subject: [PATCH 36/96] ARM: dts: meson8: Add the PWM_C (DV9) and PWM_D pins
There are some Meson8m2 boards which don't use a PMIC (like Ricoh
RN5T618) but use two PWM regulators for VCCK and VDDEE. Add the PWM_C
(DV9) and PWM_D pins so the pinctrl settings can be applied on those
boards.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index d925bdcc0..454c35530 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -479,6 +479,22 @@ gpio: banks@80b0 {
gpio-ranges = <&pinctrl_cbus 0 0 120>;
};
+ pwm_c_dv9_pins: pwm-c-dv9 {
+ mux {
+ groups = "pwm_c_dv9";
+ function = "pwm_c";
+ bias-disable;
+ };
+ };
+
+ pwm_d_pins: pwm-d {
+ mux {
+ groups = "pwm_d";
+ function = "pwm_d";
+ bias-disable;
+ };
+ };
+
sd_a_pins: sd-a {
mux {
groups = "sd_d0_a", "sd_d1_a", "sd_d2_a",
--
2.45.1

View File

@@ -0,0 +1,33 @@
From 875ed8762a46e7f0fd143b58a3002c3a76b805cd Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 22:16:15 +0200
Subject: [PATCH 45/96] dt-bindings: display: meson-vpu: add support for
Meson8/8b/8m2 - WiP
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
.../devicetree/bindings/display/amlogic,meson-vpu.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
index c9ab01434..96c32747e 100644
--- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.yaml
@@ -66,8 +66,12 @@ properties:
- const: amlogic,meson-gx-vpu
- enum:
- amlogic,meson-g12a-vpu # G12A (S905X2, S905Y2, S905D2)
+ - amlogic,meson8-vpu
+ - amlogic,meson8b-vpu
+ - amlogic,meson8m2-vpu
reg:
+ minItems: 1
maxItems: 2
reg-names:
--
2.45.1

View File

@@ -0,0 +1,39 @@
From f4fdd1b75e3ad64c9903a42aeeb9e45a1ad10780 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 21:50:45 +0200
Subject: [PATCH 46/96] drm/meson: add Meson8/Meson8b/Meson8m2 specific
vpu_compatible entries
Add values for Meson8/Meson8b/Meson8m2 to enum vpu_compatible so quirks
for these earlier hardware generations can be added to the driver.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.h | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 69be4c67f..8e1c01242 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -20,10 +20,13 @@ struct phy;
struct platform_device;
enum vpu_compatible {
- VPU_COMPATIBLE_GXBB = 0,
- VPU_COMPATIBLE_GXL = 1,
- VPU_COMPATIBLE_GXM = 2,
- VPU_COMPATIBLE_G12A = 3,
+ VPU_COMPATIBLE_M8 = 0,
+ VPU_COMPATIBLE_M8B = 1,
+ VPU_COMPATIBLE_M8M2 = 2,
+ VPU_COMPATIBLE_GXBB = 3,
+ VPU_COMPATIBLE_GXL = 4,
+ VPU_COMPATIBLE_GXM = 5,
+ VPU_COMPATIBLE_G12A = 6,
};
enum {
--
2.45.1

View File

@@ -0,0 +1,67 @@
From 31af191867e9272d80820cc452e3c209a24713fa Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 26 Apr 2020 00:00:09 +0200
Subject: [PATCH 47/96] drm/meson: Use 24 bits per pixel for the framebuffer on
Meson8/8b/8m2
All SoC generations before GXBB don't have a way to configure the
alpha value for DRM_FORMAT_XRGB8888 and DRM_FORMAT_XBGR8888. These
formats have an X component instead of an alpha component. On
Meson8/8b/8m2 there is no way to configure the alpha value to use
instead of the X component. This results in the fact that the
formats with X component are only supported on GXBB and newer. Use
24 bits per pixel and therefore DRM_FORMAT_RGB888 to get a
working framebuffer console.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 17a5cca00..60298cf3b 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -159,6 +159,30 @@ static void meson_vpu_init(struct meson_drm *priv)
writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
}
+static void meson_fbdev_setup(struct meson_drm *priv)
+{
+ unsigned int preferred_bpp;
+
+ /*
+ * All SoC generations before GXBB don't have a way to configure the
+ * alpha value for DRM_FORMAT_XRGB8888 and DRM_FORMAT_XBGR8888. These
+ * formats have an X component instead of an alpha component. On
+ * Meson8/8b/8m2 there is no way to configure the alpha value to use
+ * instead of the X component. This results in the fact that the
+ * formats with X component are only supported on GXBB and newer. Use
+ * 24 bits per pixel and therefore DRM_FORMAT_RGB888 to get a
+ * working framebuffer console.
+ */
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2))
+ preferred_bpp = 24;
+ else
+ preferred_bpp = 32;
+
+ drm_fbdev_dma_setup(priv->drm, preferred_bpp);
+}
+
struct meson_drm_soc_attr {
struct meson_drm_soc_limits limits;
const struct soc_device_attribute *attrs;
@@ -362,7 +386,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (ret)
goto uninstall_irq;
- drm_fbdev_dma_setup(drm, 32);
+ meson_fbdev_setup(priv);
return 0;
--
2.45.1

View File

@@ -0,0 +1,84 @@
From fc19ccbb10a7f76c8ad92571f306782c4afebe3c Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 21:53:21 +0200
Subject: [PATCH 48/96] drm/meson: Use a separate list of supported formats for
32-bit SoCs
The VIU_OSD1_CTRL_STAT2 and VIU_OSD2_CTRL_STAT2 registers on
Meson8/Meson8b/Meson8m2 don't have the following bits:
- replaced_alpha_en in bit [14]
- replaced_alpha in bits [13:6]
This results in formats with X component (currently DRM_FORMAT_XRGB8888
and DRM_FORMAT_XBGR8888 are supported on GXBB and later) are not
supported. Depending on the application this may work (kmscube for
example - which seems to properly set 0xff as alpha component), but
there's other examples (Kodi for example) where there are alpha blending
issues because the alpha value is not defined (and thus some random
value).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_plane.c | 30 ++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index 815dfe304..e71503609 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -471,7 +471,20 @@ static const struct drm_plane_funcs meson_plane_funcs = {
.format_mod_supported = meson_plane_format_mod_supported,
};
-static const uint32_t supported_drm_formats[] = {
+/*
+ * X components (for example in DRM_FORMAT_XRGB8888 and DRM_FORMAT_XBGR8888)
+ * are not supported because these older SoC's are lacking the OSD_REPLACE_EN
+ * bit to replace the X alpha component with a static value, leaving the alpha
+ * component in an undefined state.
+ */
+static const uint32_t supported_drm_formats_m8[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGB565,
+};
+
+static const uint32_t supported_drm_formats_gx[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB8888,
@@ -533,6 +546,8 @@ int meson_plane_create(struct meson_drm *priv)
{
struct meson_plane *meson_plane;
struct drm_plane *plane;
+ unsigned int num_drm_formats;
+ const uint32_t *drm_formats;
const uint64_t *format_modifiers = format_modifiers_default;
meson_plane = devm_kzalloc(priv->drm->dev, sizeof(*meson_plane),
@@ -548,10 +563,19 @@ int meson_plane_create(struct meson_drm *priv)
else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A))
format_modifiers = format_modifiers_afbc_g12a;
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ drm_formats = supported_drm_formats_m8;
+ num_drm_formats = ARRAY_SIZE(supported_drm_formats_m8);
+ } else {
+ drm_formats = supported_drm_formats_gx;
+ num_drm_formats = ARRAY_SIZE(supported_drm_formats_gx);
+ }
+
drm_universal_plane_init(priv->drm, plane, 0xFF,
&meson_plane_funcs,
- supported_drm_formats,
- ARRAY_SIZE(supported_drm_formats),
+ drm_formats, num_drm_formats,
format_modifiers,
DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane");
--
2.45.1

View File

@@ -0,0 +1,52 @@
From 4fec04a45ba08241d76deaa2640aad5be1743683 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 31 Jan 2022 23:02:59 +0100
Subject: [PATCH 49/96] drm/meson: Skip VIU_OSD1_CTRL_STAT2 alpha replace value
initialization
The VIU_OSD1_CTRL_STAT2 and VIU_OSD2_CTRL_STAT2 registers on
Meson8/Meson8b/Meson8m2 don't have the following bits:
- replaced_alpha_en in bit [14]
- replaced_alpha in bits [13:6]
Don't initialize the replaced_alpha register bits in VIU_OSD1_CTRL_STAT2
on Meson8/Meson8b/Meson8m2 because they are not implemented on those
SoCs.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_viu.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
index cd399b0b7..bdfa342c4 100644
--- a/drivers/gpu/drm/meson/meson_viu.c
+++ b/drivers/gpu/drm/meson/meson_viu.c
@@ -448,13 +448,17 @@ void meson_viu_init(struct meson_drm *priv)
writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT));
- /* Set OSD alpha replace value */
- writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
- 0xff << OSD_REPLACE_SHIFT,
- priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
- writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
- 0xff << OSD_REPLACE_SHIFT,
- priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
+ if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) &&
+ !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) &&
+ !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ /* Set OSD alpha replace value */
+ writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
+ 0xff << OSD_REPLACE_SHIFT,
+ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
+ writel_bits_relaxed(0xff << OSD_REPLACE_SHIFT,
+ 0xff << OSD_REPLACE_SHIFT,
+ priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
+ }
/* Disable VD1 AFBC */
/* di_mif0_en=0 mif0_to_vpp_en=0 di_mad_en=0 and afbc vd1 set=0*/
--
2.45.1

View File

@@ -0,0 +1,35 @@
From a7583cc8a459b072fb3613f204143bcfccd18849 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 22:00:57 +0200
Subject: [PATCH 50/96] drm/meson: Enable the RGB to YUV converter on
Meson8/Meson8b/Meson8m2
Set VIU_OSD1_BLK0_CFG_W0[7] to 1 to enable RGB to YUV converter, just
like on GXBB.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_plane.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index e71503609..27e395772 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -200,8 +200,11 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
priv->viu.osd1_ctrl_stat2 &= ~OSD_DPATH_MALI_AFBCD;
}
- /* On GXBB, Use the old non-HDR RGB2YUV converter */
- if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
+ /* On GXBB and earlier, Use the old non-HDR RGB2YUV converter */
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
priv->viu.osd1_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB;
if (priv->viu.osd1_afbcd &&
--
2.45.1

View File

@@ -0,0 +1,85 @@
From 8b09602979c279f579ced2d5234f878e8e9243bb Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 22:03:27 +0200
Subject: [PATCH 51/96] drm/meson: Update meson_vpu_init to work with
Meson8/Meson8b/Meson8m2
Don't modify the VPU_RDARB_MODE_* registers because they only exist on
GXBB and newer SoCs. Initialize the VPU_MEM_PD_REG0 and VPU_MEM_PD_REG1
to 0x0 (meaning: enable everything), just like vendor u-boot does for
Meson8/Meson8b/Meson8m2.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.c | 55 ++++++++++++++++++-------------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 60298cf3b..ffc5eb588 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -135,28 +135,39 @@ static struct regmap_config meson_regmap_config = {
static void meson_vpu_init(struct meson_drm *priv)
{
- u32 value;
-
- /*
- * Slave dc0 and dc5 connected to master port 1.
- * By default other slaves are connected to master port 0.
- */
- value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) |
- VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1);
- writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
-
- /* Slave dc0 connected to master port 1 */
- value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1);
- writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
-
- /* Slave dc4 and dc7 connected to master port 1 */
- value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) |
- VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1);
- writel_relaxed(value, priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
-
- /* Slave dc1 connected to master port 1 */
- value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1);
- writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ writel(0x0, priv->io_base + _REG(VPU_MEM_PD_REG0));
+ writel(0x0, priv->io_base + _REG(VPU_MEM_PD_REG1));
+ } else {
+ u32 value;
+
+ /*
+ * Slave dc0 and dc5 connected to master port 1.
+ * By default other slaves are connected to master port 0.
+ */
+ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1) |
+ VPU_RDARB_SLAVE_TO_MASTER_PORT(5, 1);
+ writel_relaxed(value,
+ priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
+
+ /* Slave dc0 connected to master port 1 */
+ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(0, 1);
+ writel_relaxed(value,
+ priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
+
+ /* Slave dc4 and dc7 connected to master port 1 */
+ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(4, 1) |
+ VPU_RDARB_SLAVE_TO_MASTER_PORT(7, 1);
+ writel_relaxed(value,
+ priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
+
+ /* Slave dc1 connected to master port 1 */
+ value = VPU_RDARB_SLAVE_TO_MASTER_PORT(1, 1);
+ writel_relaxed(value,
+ priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
+ }
}
static void meson_fbdev_setup(struct meson_drm *priv)
--
2.45.1

View File

@@ -0,0 +1,57 @@
From 7017db5123fbbccca0dde37e7a2f45172d50e56e Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 23 Dec 2020 21:18:35 +0100
Subject: [PATCH 52/96] drm/meson: Describe the HDMI PHY frequency limits of
Meson8/8b/8m2
The maximum HDMI PLL frequency used by the vendor kernel is 2.976GHz.
For Meson8 and Meson8b (both "HDMI 1.4 4k" capable) the maximum HDMI PHY
frequency therefore is 2.976GHz. This makes sure we don't expose any
HDMI 2.0 modes.
Meson8b only supports up to 1080p according to it's datasheet. Limit the
Meson8b SoC's to 1.65GHz (similar to what's already there for GXL S805X
and S805Y).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index ffc5eb588..bbb8b8b50 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -200,13 +200,29 @@ struct meson_drm_soc_attr {
};
static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = {
- /* S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz */
+ /* The maximum frequency of HDMI PHY on Meson8 and Meson8m2 is ~3GHz */
+ {
+ .limits = {
+ .max_hdmi_phy_freq = 2976000,
+ },
+ .attrs = (const struct soc_device_attribute []) {
+ { .soc_id = "Meson8 (S802)", },
+ { .soc_id = "Meson8m2 (S812)", },
+ { /* sentinel */ },
+ }
+ },
+ /*
+ * GXL S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz.
+ * Meson8b (S805) only supports "1200p@60 max resolution" according to
+ * the public datasheet.
+ */
{
.limits = {
.max_hdmi_phy_freq = 1650000,
},
.attrs = (const struct soc_device_attribute []) {
{ .soc_id = "GXL (S805*)", },
+ { .soc_id = "Meson8b (S805)", },
{ /* sentinel */ }
}
},
--
2.45.1

View File

@@ -0,0 +1,144 @@
From e37f5e8c60f9ecad4b2286bec22e2989d267971b Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 6 Oct 2021 23:34:04 +0200
Subject: [PATCH 53/96] drm/meson: Update the HDMI encoder for Meson8/8b/8m2
Meson8/8b/8m2 uses VPU_HDMI_OUTPUT_YCBCR for YUV444 while newer SoCs use
VPU_HDMI_OUTPUT_CBYCR. Also the 32-bit SoCs use VPU_HDMI_OUTPUT_CRYCB
for RGB. These are the only two known mappings for the 32-bit SoCs.
The VPU_HDMI_FMT_CTRL register with it's YUV444 to YUV422/YUV420
converter is not present on these older SoCs. Avoid writing this
reserved register on these 32-bit SoCs.
MEDIA_BUS_FMT_RGB888_1X24 cannot be exposed as output format because the
RGB to YUV converter is always enabled in meson_plane_atomic_update()
(so there's currently no way to configure it).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_encoder_hdmi.c | 66 ++++++++++++++++------
1 file changed, 49 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
index 0593a1cde..d8aae0952 100644
--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
@@ -190,13 +190,13 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge,
{
struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
struct drm_atomic_state *state = bridge_state->base.state;
- unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR;
struct meson_drm *priv = encoder_hdmi->priv;
struct drm_connector_state *conn_state;
const struct drm_display_mode *mode;
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
bool yuv420_mode = false;
+ unsigned int ycrcb_map;
int vic;
connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
@@ -217,11 +217,21 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge,
dev_dbg(priv->dev, "\"%s\" vic %d\n", mode->name, vic);
- if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_RGB888_1X24)
+ ycrcb_map = VPU_HDMI_OUTPUT_YCBCR;
+ else
+ ycrcb_map = VPU_HDMI_OUTPUT_CRYCB;
+ } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
ycrcb_map = VPU_HDMI_OUTPUT_CRYCB;
yuv420_mode = true;
- } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16)
+ } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) {
ycrcb_map = VPU_HDMI_OUTPUT_CRYCB;
+ } else {
+ ycrcb_map = VPU_HDMI_OUTPUT_CBYCR;
+ }
/* VENC + VENC-DVI Mode setup */
meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode);
@@ -229,17 +239,21 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge,
/* VCLK Set clock */
meson_encoder_hdmi_set_vclk(encoder_hdmi, mode);
- if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
- /* Setup YUV420 to HDMI-TX, no 10bit diphering */
- writel_relaxed(2 | (2 << 2),
- priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
- else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16)
- /* Setup YUV422 to HDMI-TX, no 10bit diphering */
- writel_relaxed(1 | (2 << 2),
- priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
- else
- /* Setup YUV444 to HDMI-TX, no 10bit diphering */
- writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+ if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) &&
+ !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) &&
+ !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
+ /* Setup YUV420 to HDMI-TX, no 10bit diphering */
+ writel_relaxed(2 | (2 << 2),
+ priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+ else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16)
+ /* Setup YUV422 to HDMI-TX, no 10bit diphering */
+ writel_relaxed(1 | (2 << 2),
+ priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+ else
+ /* Setup YUV444 to HDMI-TX, no 10bit diphering */
+ writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+ }
dev_dbg(priv->dev, "%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
@@ -262,7 +276,11 @@ static void meson_encoder_hdmi_atomic_disable(struct drm_bridge *bridge,
writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
}
-static const u32 meson_encoder_hdmi_out_bus_fmts[] = {
+static const u32 meson8_encoder_hdmi_out_bus_fmts[] = {
+ MEDIA_BUS_FMT_YUV8_1X24,
+};
+
+static const u32 meson_gx_encoder_hdmi_out_bus_fmts[] = {
MEDIA_BUS_FMT_YUV8_1X24,
MEDIA_BUS_FMT_UYVY8_1X16,
MEDIA_BUS_FMT_UYYVYY8_0_5X24,
@@ -276,13 +294,27 @@ meson_encoder_hdmi_get_inp_bus_fmts(struct drm_bridge *bridge,
u32 output_fmt,
unsigned int *num_input_fmts)
{
+ struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
+ struct meson_drm *priv = encoder_hdmi->priv;
+ unsigned int num_out_bus_fmts;
+ const u32 *out_bus_fmts;
u32 *input_fmts = NULL;
int i;
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ num_out_bus_fmts = ARRAY_SIZE(meson8_encoder_hdmi_out_bus_fmts);
+ out_bus_fmts = meson8_encoder_hdmi_out_bus_fmts;
+ } else {
+ num_out_bus_fmts = ARRAY_SIZE(meson_gx_encoder_hdmi_out_bus_fmts);
+ out_bus_fmts = meson_gx_encoder_hdmi_out_bus_fmts;
+ }
+
*num_input_fmts = 0;
- for (i = 0 ; i < ARRAY_SIZE(meson_encoder_hdmi_out_bus_fmts) ; ++i) {
- if (output_fmt == meson_encoder_hdmi_out_bus_fmts[i]) {
+ for (i = 0 ; i < num_out_bus_fmts ; ++i) {
+ if (output_fmt == out_bus_fmts[i]) {
*num_input_fmts = 1;
input_fmts = kcalloc(*num_input_fmts,
sizeof(*input_fmts),
--
2.45.1

View File

@@ -0,0 +1,34 @@
From 7ba0841fd85b2f8fd11602ea92fb8887ecd3d81c Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Wed, 6 Oct 2021 23:37:44 +0200
Subject: [PATCH 54/96] drm/meson: Only set ycbcr_420_allowed on 64-bit SoCs
The 32-bit SoCs don't support YUV420 so we don't enable that
functionality there.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_encoder_hdmi.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
index d8aae0952..4a84d7d99 100644
--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
@@ -481,8 +481,11 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
drm_connector_attach_max_bpc_property(meson_encoder_hdmi->connector, 8, 8);
- /* Handle this here until handled by drm_bridge_connector_init() */
- meson_encoder_hdmi->connector->ycbcr_420_allowed = true;
+ if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) &&
+ !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) &&
+ !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2))
+ /* Handle this here until handled by drm_bridge_connector_init() */
+ meson_encoder_hdmi->connector->ycbcr_420_allowed = true;
pdev = of_find_device_by_node(remote);
of_node_put(remote);
--
2.45.1

View File

@@ -0,0 +1,100 @@
From 39042addabb9910ec95e916fb619f5af8097f0c8 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Thu, 7 Oct 2021 19:09:49 +0200
Subject: [PATCH 55/96] drm/meson: Make the HHI registers optional - WIP
The HHI area contains the clock controller registers as well as the
registers for the CVBS DAC. Make the HHI registers optional because the
functionality provided by them can be handled by separate drivers
(especially on the 32-bit SoCs).
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.c | 35 ++++++++++++++++--------------
drivers/gpu/drm/meson/meson_venc.c | 11 +++++++---
2 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index bbb8b8b50..104b53861 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -271,24 +271,27 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
priv->io_base = regs;
+ /*
+ * The HHI resource is optional because it contains the clocks and CVBS
+ * encoder registers. These are managed by separate drivers though.
+ */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi");
- 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;
- goto free_drm;
- }
+ if (res) {
+ /* Simply ioremap since it may be a shared register zone */
+ regs = devm_ioremap(dev, res->start, resource_size(res));
+ if (!regs) {
+ ret = -EADDRNOTAVAIL;
+ goto free_drm;
+ }
- priv->hhi = devm_regmap_init_mmio(dev, regs,
- &meson_regmap_config);
- if (IS_ERR(priv->hhi)) {
- dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
- ret = PTR_ERR(priv->hhi);
- goto free_drm;
+ priv->hhi = devm_regmap_init_mmio(dev, regs,
+ &meson_regmap_config);
+ if (IS_ERR(priv->hhi)) {
+ dev_err(&pdev->dev,
+ "Couldn't create the HHI regmap\n");
+ ret = PTR_ERR(priv->hhi);
+ goto free_drm;
+ }
}
priv->canvas = meson_canvas_get(dev);
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 5efd7a298..805751b9e 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -1953,12 +1953,16 @@ void meson_venc_enable_vsync(struct meson_drm *priv)
writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN,
priv->io_base + _REG(VENC_INTCTRL));
}
- regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25));
+
+ if (priv->hhi)
+ regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25));
}
void meson_venc_disable_vsync(struct meson_drm *priv)
{
- regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), 0);
+ if (priv->hhi)
+ regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), 0);
+
writel_relaxed(0, priv->io_base + _REG(VENC_INTCTRL));
}
@@ -1968,7 +1972,8 @@ void meson_venc_init(struct meson_drm *priv)
writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
/* Disable HDMI PHY */
- regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
+ if (priv->hhi)
+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
/* Disable HDMI */
writel_bits_relaxed(VPU_HDMI_ENCI_DATA_TO_HDMI |
--
2.45.1

View File

@@ -0,0 +1,485 @@
From f105e98570211cb16a2ffdca32ac2869c92f9353 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 22:13:51 +0200
Subject: [PATCH 57/96] drm/meson: Meson8/Meson8b/Meson8m2 VCLK - HACK
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.c | 101 ++++++++++++++++++--
drivers/gpu/drm/meson/meson_drv.h | 32 +++++++
drivers/gpu/drm/meson/meson_vclk.c | 146 +++++++++++++++++++++++++++++
drivers/gpu/drm/meson/meson_venc.c | 24 ++++-
4 files changed, 293 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 104b53861..2fb074e53 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -170,6 +170,35 @@ static void meson_vpu_init(struct meson_drm *priv)
}
}
+static int meson_video_clock_init(struct meson_drm *priv)
+{
+ int ret;
+
+ ret = clk_bulk_prepare(VPU_VID_CLK_NUM, priv->vid_clks);
+ if (ret)
+ return dev_err_probe(priv->dev, ret,
+ "Failed to prepare the video clocks\n");
+
+ ret = clk_bulk_prepare(priv->num_intr_clks, priv->intr_clks);
+ if (ret)
+ return dev_err_probe(priv->dev, ret,
+ "Failed to prepare the interrupt clocks\n");
+
+ return 0;
+}
+
+static void meson_video_clock_exit(struct meson_drm *priv)
+{
+ if (priv->clk_dac_enabled)
+ clk_disable(priv->clk_dac);
+
+ if (priv->clk_venc_enabled)
+ clk_disable(priv->clk_venc);
+
+ clk_bulk_unprepare(priv->num_intr_clks, priv->intr_clks);
+ clk_bulk_unprepare(VPU_VID_CLK_NUM, priv->vid_clks);
+}
+
static void meson_fbdev_setup(struct meson_drm *priv)
{
unsigned int preferred_bpp;
@@ -263,10 +292,59 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
priv->compat = match->compat;
priv->afbcd.ops = match->afbcd_ops;
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ priv->vid_pll_resets[VPU_RESET_VID_PLL_PRE].id = "vid_pll_pre";
+ priv->vid_pll_resets[VPU_RESET_VID_PLL_POST].id = "vid_pll_post";
+ priv->vid_pll_resets[VPU_RESET_VID_PLL_SOFT_PRE].id = "vid_pll_soft_pre";
+ priv->vid_pll_resets[VPU_RESET_VID_PLL_SOFT_POST].id = "vid_pll_soft_post";
+
+ ret = devm_reset_control_bulk_get_exclusive(dev,
+ VPU_RESET_VID_PLL_NUM,
+ priv->vid_pll_resets);
+ if (ret)
+ goto free_drm;
+
+ priv->intr_clks[0].id = "vpu_intr";
+ priv->intr_clks[1].id = "hdmi_intr_sync";
+ priv->intr_clks[2].id = "venci_int";
+ priv->num_intr_clks = 3;
+
+ ret = devm_clk_bulk_get(dev, priv->num_intr_clks,
+ priv->intr_clks);
+ if (ret)
+ goto free_drm;
+
+ priv->vid_clks[VPU_VID_CLK_TMDS].id = "tmds";
+ priv->vid_clks[VPU_VID_CLK_HDMI_TX_PIXEL].id = "hdmi_tx_pixel";
+ priv->vid_clks[VPU_VID_CLK_CTS_ENCP].id = "cts_encp";
+ priv->vid_clks[VPU_VID_CLK_CTS_ENCI].id = "cts_enci";
+ priv->vid_clks[VPU_VID_CLK_CTS_ENCT].id = "cts_enct";
+ priv->vid_clks[VPU_VID_CLK_CTS_ENCL].id = "cts_encl";
+ priv->vid_clks[VPU_VID_CLK_CTS_VDAC0].id = "cts_vdac0";
+
+ ret = devm_clk_bulk_get(dev, VPU_VID_CLK_NUM, priv->vid_clks);
+ if (ret)
+ goto free_drm;
+ } else {
+ priv->intr_clks[0].id = "vpu_intr";
+ priv->num_intr_clks = 1;
+
+ ret = devm_clk_bulk_get_optional(dev, priv->num_intr_clks,
+ priv->intr_clks);
+ if (ret)
+ goto free_drm;
+ }
+
+ ret = meson_video_clock_init(priv);
+ if (ret)
+ goto free_drm;
+
regs = devm_platform_ioremap_resource_byname(pdev, "vpu");
if (IS_ERR(regs)) {
ret = PTR_ERR(regs);
- goto free_drm;
+ goto video_clock_exit;
}
priv->io_base = regs;
@@ -281,7 +359,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs) {
ret = -EADDRNOTAVAIL;
- goto free_drm;
+ goto video_clock_exit;
}
priv->hhi = devm_regmap_init_mmio(dev, regs,
@@ -290,36 +368,36 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
dev_err(&pdev->dev,
"Couldn't create the HHI regmap\n");
ret = PTR_ERR(priv->hhi);
- goto free_drm;
+ goto video_clock_exit;
}
}
priv->canvas = meson_canvas_get(dev);
if (IS_ERR(priv->canvas)) {
ret = PTR_ERR(priv->canvas);
- goto free_drm;
+ goto video_clock_exit;
}
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
if (ret)
- goto free_drm;
+ goto video_clock_exit;
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
if (ret) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
- goto free_drm;
+ goto video_clock_exit;
}
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1);
if (ret) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
- goto free_drm;
+ goto video_clock_exit;
}
ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2);
if (ret) {
meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
- goto free_drm;
+ goto video_clock_exit;
}
priv->vsync_irq = platform_get_irq(pdev, 0);
@@ -425,6 +503,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
exit_afbcd:
if (priv->afbcd.ops)
priv->afbcd.ops->exit(priv);
+video_clock_exit:
+ meson_video_clock_exit(priv);
free_drm:
drm_dev_put(drm);
@@ -469,6 +549,8 @@ static void meson_drv_unbind(struct device *dev)
if (priv->afbcd.ops)
priv->afbcd.ops->exit(priv);
+
+ meson_video_clock_exit(priv);
}
static const struct component_master_ops meson_drv_master_ops = {
@@ -483,6 +565,8 @@ static int __maybe_unused meson_drv_pm_suspend(struct device *dev)
if (!priv)
return 0;
+ // TODO: video clock suspend
+
return drm_mode_config_helper_suspend(priv->drm);
}
@@ -493,6 +577,7 @@ static int __maybe_unused meson_drv_pm_resume(struct device *dev)
if (!priv)
return 0;
+ meson_video_clock_init(priv);
meson_vpu_init(priv);
meson_venc_init(priv);
meson_vpp_init(priv);
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 8e1c01242..59f80fcc6 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -7,9 +7,11 @@
#ifndef __MESON_DRV_H
#define __MESON_DRV_H
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
struct drm_crtc;
struct drm_device;
@@ -45,6 +47,25 @@ struct meson_drm_soc_limits {
unsigned int max_hdmi_phy_freq;
};
+enum vpu_bulk_clk_id {
+ VPU_VID_CLK_TMDS = 0,
+ VPU_VID_CLK_HDMI_TX_PIXEL,
+ VPU_VID_CLK_CTS_ENCP,
+ VPU_VID_CLK_CTS_ENCI,
+ VPU_VID_CLK_CTS_ENCT,
+ VPU_VID_CLK_CTS_ENCL,
+ VPU_VID_CLK_CTS_VDAC0,
+ VPU_VID_CLK_NUM
+};
+
+enum vpu_bulk_vid_pll_reset_id {
+ VPU_RESET_VID_PLL_PRE = 0,
+ VPU_RESET_VID_PLL_POST,
+ VPU_RESET_VID_PLL_SOFT_PRE,
+ VPU_RESET_VID_PLL_SOFT_POST,
+ VPU_RESET_VID_PLL_NUM
+};
+
struct meson_drm {
struct device *dev;
enum vpu_compatible compat;
@@ -70,6 +91,17 @@ struct meson_drm {
bool cvbs_dac_enabled;
struct platform_device *cvbs_dac_pdev;
+ struct clk_bulk_data intr_clks[3];
+ unsigned int num_intr_clks;
+ bool intr_clks_enabled;
+ struct clk_bulk_data vid_clks[VPU_VID_CLK_NUM];
+ bool vid_clk_rate_exclusive[VPU_VID_CLK_NUM];
+ struct clk *clk_venc;
+ bool clk_venc_enabled;
+ struct clk *clk_dac;
+ bool clk_dac_enabled;
+ struct reset_control_bulk_data vid_pll_resets[VPU_RESET_VID_PLL_NUM];
+
/* Components Data */
struct {
bool osd1_enabled;
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index 2a82119eb..a2c1bf1ae 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -732,6 +732,11 @@ meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq)
return MODE_CLOCK_HIGH;
}
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2))
+ return MODE_OK;
+
if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
return MODE_OK;
@@ -784,6 +789,11 @@ meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
return MODE_CLOCK_HIGH;
}
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2))
+ return MODE_OK;
+
for (i = 0 ; params[i].pixel_freq ; ++i) {
DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
i, params[i].pixel_freq,
@@ -1024,6 +1034,128 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
}
+static int meson_vclk_set_rate_exclusive(struct meson_drm *priv,
+ enum vpu_bulk_clk_id clk_id,
+ unsigned int rate_khz)
+{
+ struct clk *clk = priv->vid_clks[clk_id].clk;
+ int ret;
+
+ ret = clk_set_rate_exclusive(clk, rate_khz * 1000UL);
+ if (ret)
+ return ret;
+
+ priv->vid_clk_rate_exclusive[clk_id] = true;
+
+ return 0;
+}
+
+static void meson_vclk_disable_ccf(struct meson_drm *priv)
+{
+ unsigned int i;
+
+ /* allow all clocks to be changed in _enable again */
+ for (i = 0; i < VPU_VID_CLK_NUM; i++) {
+ if (!priv->vid_clk_rate_exclusive[i])
+ continue;
+
+ clk_rate_exclusive_put(priv->vid_clks[i].clk);
+ priv->vid_clk_rate_exclusive[i] = false;
+ }
+
+ if (priv->clk_dac_enabled) {
+ clk_disable(priv->clk_dac);
+ priv->clk_dac_enabled = false;
+ }
+
+ if (priv->clk_venc_enabled) {
+ clk_disable(priv->clk_venc);
+ priv->clk_venc_enabled = false;
+ }
+}
+
+static int meson_vclk_enable_ccf(struct meson_drm *priv, unsigned int target,
+ bool hdmi_use_enci, unsigned int phy_freq,
+ unsigned int dac_freq, unsigned int venc_freq)
+{
+ enum vpu_bulk_clk_id venc_clk_id, dac_clk_id;
+ int ret;
+
+ if (target == MESON_VCLK_TARGET_CVBS || hdmi_use_enci)
+ venc_clk_id = VPU_VID_CLK_CTS_ENCI;
+ else
+ venc_clk_id = VPU_VID_CLK_CTS_ENCP;
+
+ if (target == MESON_VCLK_TARGET_CVBS)
+ dac_clk_id = VPU_VID_CLK_CTS_VDAC0;
+ else
+ dac_clk_id = VPU_VID_CLK_HDMI_TX_PIXEL;
+
+ /*
+ * The TMDS clock also updates the PLL. Protect the PLL rate so all
+ * following clocks are derived from the PLL setting which matches the
+ * TMDS clock.
+ */
+ ret = meson_vclk_set_rate_exclusive(priv, VPU_VID_CLK_TMDS, phy_freq);
+ if (ret) {
+ dev_err(priv->dev, "Failed to set TMDS clock to %ukHz: %d\n",
+ phy_freq, ret);
+ goto out_enable_clocks;
+ }
+
+ /*
+ * The DAC clock may be derived from a parent of the VENC clock so we
+ * must protect the VENC clock from changing it's rate. This works
+ * because the DAC freq can be divided by the VENC clock.
+ */
+ ret = meson_vclk_set_rate_exclusive(priv, venc_clk_id, venc_freq);
+ if (ret) {
+ dev_warn(priv->dev,
+ "Failed to set VENC clock to %ukHz while TMDS clock is %ukHz: %d\n",
+ venc_freq, phy_freq, ret);
+ goto out_enable_clocks;
+ }
+
+ priv->clk_venc = priv->vid_clks[venc_clk_id].clk;
+
+ /*
+ * after changing any of the VID_PLL_* clocks (which can happen when
+ * update the VENC clock rate) we need to assert and then de-assert the
+ * VID_DIVIDER_CNTL_* reset lines.
+ */
+ reset_control_bulk_assert(VPU_RESET_VID_PLL_NUM, priv->vid_pll_resets);
+ reset_control_bulk_deassert(VPU_RESET_VID_PLL_NUM, priv->vid_pll_resets);
+
+ ret = meson_vclk_set_rate_exclusive(priv, dac_clk_id, dac_freq);
+ if (ret) {
+ dev_warn(priv->dev,
+ "Failed to set pixel clock to %ukHz while TMDS clock is %ukHz: %d\n",
+ dac_freq, phy_freq, ret);
+ goto out_enable_clocks;
+ }
+
+ priv->clk_dac = priv->vid_clks[dac_clk_id].clk;
+
+out_enable_clocks:
+ ret = clk_enable(priv->clk_venc);
+ if (ret)
+ dev_err(priv->dev,
+ "Failed to re-enable the VENC clock at %ukHz: %d\n",
+ venc_freq, ret);
+ else
+ priv->clk_venc_enabled = true;
+
+ ret = clk_enable(priv->clk_dac);
+ if (ret)
+ dev_err(priv->dev,
+ "Failed to re-enable the pixel clock at %ukHz: %d\n",
+ dac_freq, ret);
+ else
+ priv->clk_dac_enabled = true;
+
+ return ret;
+}
+
void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int phy_freq, unsigned int vclk_freq,
unsigned int venc_freq, unsigned int dac_freq,
@@ -1034,6 +1166,20 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int hdmi_tx_div;
unsigned int venc_div;
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) {
+ /* CVBS video clocks are generated off a 1296MHz base clock */
+ if (target == MESON_VCLK_TARGET_CVBS)
+ phy_freq = 1296000;
+
+ dev_err(priv->dev, "%s(target: %u, phy: %u, dac: %u, venc: %u, hdmi_use_enci: %u)\n", __func__, target, phy_freq, dac_freq, venc_freq, hdmi_use_enci);
+ meson_vclk_disable_ccf(priv);
+ meson_vclk_enable_ccf(priv, target, hdmi_use_enci, phy_freq,
+ dac_freq, venc_freq);
+ return;
+ }
+
if (target == MESON_VCLK_TARGET_CVBS) {
meson_venci_cvbs_clock_config(priv);
return;
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 805751b9e..d834359c1 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -1954,14 +1954,34 @@ void meson_venc_enable_vsync(struct meson_drm *priv)
priv->io_base + _REG(VENC_INTCTRL));
}
- if (priv->hhi)
+ if (priv->intr_clks[0].clk) {
+ if (!priv->intr_clks_enabled) {
+ int ret;
+
+ ret = clk_bulk_enable(priv->num_intr_clks,
+ priv->intr_clks);
+ if (ret)
+ dev_err(priv->dev,
+ "Failed to enable the interrupt clocks\n");
+ else
+ priv->intr_clks_enabled = true;
+ }
+ } else {
regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25));
+ }
}
void meson_venc_disable_vsync(struct meson_drm *priv)
{
- if (priv->hhi)
+ if (priv->intr_clks[0].clk) {
+ if (priv->intr_clks_enabled) {
+ clk_bulk_disable(priv->num_intr_clks,
+ priv->intr_clks);
+ priv->intr_clks_enabled = false;
+ }
+ } else {
regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), 0);
+ }
writel_relaxed(0, priv->io_base + _REG(VENC_INTCTRL));
}
--
2.45.1

View File

@@ -0,0 +1,52 @@
From 8717397eb0cad729cc6244019665476aec47dbaf Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Apr 2020 22:14:27 +0200
Subject: [PATCH 58/96] drm/meson: Enable support for Meson8/Meson8b/Meson8m2
Add a compatible string for each of the three SoCs now that all hardware
specific quirks are added to the driver.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/gpu/drm/meson/meson_drv.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index 2fb074e53..3a853fa25 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -660,6 +660,18 @@ static void meson_drv_remove(struct platform_device *pdev)
component_master_del(&pdev->dev, &meson_drv_master_ops);
}
+static struct meson_drm_match_data meson_drm_m8_data = {
+ .compat = VPU_COMPATIBLE_M8,
+};
+
+static struct meson_drm_match_data meson_drm_m8b_data = {
+ .compat = VPU_COMPATIBLE_M8B,
+};
+
+static struct meson_drm_match_data meson_drm_m8m2_data = {
+ .compat = VPU_COMPATIBLE_M8M2,
+};
+
static struct meson_drm_match_data meson_drm_gxbb_data = {
.compat = VPU_COMPATIBLE_GXBB,
};
@@ -679,6 +691,12 @@ static struct meson_drm_match_data meson_drm_g12a_data = {
};
static const struct of_device_id dt_match[] = {
+ { .compatible = "amlogic,meson8-vpu",
+ .data = (void *)&meson_drm_m8_data },
+ { .compatible = "amlogic,meson8b-vpu",
+ .data = (void *)&meson_drm_m8b_data },
+ { .compatible = "amlogic,meson8m2-vpu",
+ .data = (void *)&meson_drm_m8m2_data },
{ .compatible = "amlogic,meson-gxbb-vpu",
.data = (void *)&meson_drm_gxbb_data },
{ .compatible = "amlogic,meson-gxl-vpu",
--
2.45.1

View File

@@ -0,0 +1,272 @@
From 997c2fe858ecc56b1d0d2ccd56cce6c571b87d17 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 8 Dec 2018 13:50:48 +0100
Subject: [PATCH 59/96] ARM: dts: meson: add the VPU - WiP
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson.dtsi | 10 +++
arch/arm/boot/dts/amlogic/meson8.dtsi | 80 ++++++++++++++++++++++++
arch/arm/boot/dts/amlogic/meson8b.dtsi | 81 +++++++++++++++++++++++++
arch/arm/boot/dts/amlogic/meson8m2.dtsi | 4 ++
4 files changed, 175 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson.dtsi b/arch/arm/boot/dts/amlogic/meson.dtsi
index d7f50fec8..d729a06da 100644
--- a/arch/arm/boot/dts/amlogic/meson.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson.dtsi
@@ -38,6 +38,16 @@ hhi: system-controller@4000 {
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x4000 0x400>;
+
+
+ cvbs_dac: video-dac@2f4 {
+ compatible = "amlogic,meson-cvbs-dac";
+ reg = <0x2f4 0x8>;
+
+ #phy-cells = <0>;
+
+ status = "disabled";
+ };
};
aiu: audio-controller@5400 {
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index 454c35530..519443e19 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -314,6 +314,71 @@ mali: gpu@c0000 {
operating-points-v2 = <&gpu_opp_table>;
#cooling-cells = <2>; /* min followed by max */
};
+
+ vpu: vpu@100000 {
+ compatible = "amlogic,meson8-vpu";
+
+ reg = <0x100000 0x10000>;
+ reg-names = "vpu";
+
+ interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
+
+ amlogic,canvas = <&canvas>;
+
+ /*
+ * The VCLK{,2}_IN path always needs to derived from
+ * the CLKID_VID_PLL_FINAL_DIV so other clocks like
+ * MPLL1 are not used (MPLL1 is reserved for audio
+ * purposes).
+ */
+ assigned-clocks = <&clkc CLKID_VCLK_IN_SEL>,
+ <&clkc CLKID_VCLK2_IN_SEL>;
+ assigned-clock-parents = <&clkc CLKID_VID_PLL_FINAL_DIV>,
+ <&clkc CLKID_VID_PLL_FINAL_DIV>;
+
+ clocks = <&clkc CLKID_VPU_INTR>,
+ <&clkc CLKID_HDMI_INTR_SYNC>,
+ <&clkc CLKID_GCLK_VENCI_INT>,
+ <&clkc CLKID_HDMI_PLL_HDMI_OUT>,
+ <&clkc CLKID_HDMI_TX_PIXEL>,
+ <&clkc CLKID_CTS_ENCP>,
+ <&clkc CLKID_CTS_ENCI>,
+ <&clkc CLKID_CTS_ENCT>,
+ <&clkc CLKID_CTS_ENCL>,
+ <&clkc CLKID_CTS_VDAC0>;
+ clock-names = "vpu_intr",
+ "hdmi_intr_sync",
+ "venci_int",
+ "tmds",
+ "hdmi_tx_pixel",
+ "cts_encp",
+ "cts_enci",
+ "cts_enct",
+ "cts_encl",
+ "cts_vdac0";
+
+ resets = <&clkc CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE>,
+ <&clkc CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST>,
+ <&clkc CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE>,
+ <&clkc CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST>;
+ reset-names = "vid_pll_pre",
+ "vid_pll_post",
+ "vid_pll_soft_pre",
+ "vid_pll_soft_post";
+
+ phys = <&cvbs_dac>;
+ phy-names = "cvbs-dac";
+
+ power-domains = <&pwrc PWRC_MESON8_VPU_ID>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CVBS VDAC output port */
+ cvbs_vdac_port: port@0 {
+ reg = <0>;
+ };
+ };
};
}; /* end of / */
@@ -617,6 +682,17 @@ smp-sram@1ff80 {
};
};
+&cvbs_dac {
+ compatible = "amlogic,meson8-cvbs-dac", "amlogic,meson-cvbs-dac";
+
+ clocks = <&clkc CLKID_CTS_VDAC0>;
+
+ nvmem-cells = <&cvbs_trimming>;
+ nvmem-cell-names = "cvbs_trimming";
+
+ status = "okay";
+};
+
&efuse {
compatible = "amlogic,meson8-efuse";
clocks = <&clkc CLKID_EFUSE>;
@@ -626,6 +702,10 @@ temperature_calib: calib@1f4 {
/* only the upper two bytes are relevant */
reg = <0x1f4 0x4>;
};
+
+ cvbs_trimming: calib@1f8 {
+ reg = <0x1f8 0x2>;
+ };
};
&ethmac {
diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi
index 5ffedca99..87aa74675 100644
--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi
@@ -276,6 +276,71 @@ mali: gpu@c0000 {
operating-points-v2 = <&gpu_opp_table>;
#cooling-cells = <2>; /* min followed by max */
};
+
+ vpu: vpu@100000 {
+ compatible = "amlogic,meson8b-vpu";
+
+ reg = <0x100000 0x10000>;
+ reg-names = "vpu";
+
+ interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
+
+ amlogic,canvas = <&canvas>;
+
+ /*
+ * The VCLK{,2}_IN path always needs to derived from
+ * the CLKID_VID_PLL_FINAL_DIV so other clocks like
+ * MPLL1 are not used (MPLL1 is reserved for audio
+ * purposes).
+ */
+ assigned-clocks = <&clkc CLKID_VCLK_IN_SEL>,
+ <&clkc CLKID_VCLK2_IN_SEL>;
+ assigned-clock-parents = <&clkc CLKID_VID_PLL_FINAL_DIV>,
+ <&clkc CLKID_VID_PLL_FINAL_DIV>;
+
+ clocks = <&clkc CLKID_VPU_INTR>,
+ <&clkc CLKID_HDMI_INTR_SYNC>,
+ <&clkc CLKID_GCLK_VENCI_INT>,
+ <&clkc CLKID_HDMI_PLL_HDMI_OUT>,
+ <&clkc CLKID_HDMI_TX_PIXEL>,
+ <&clkc CLKID_CTS_ENCP>,
+ <&clkc CLKID_CTS_ENCI>,
+ <&clkc CLKID_CTS_ENCT>,
+ <&clkc CLKID_CTS_ENCL>,
+ <&clkc CLKID_CTS_VDAC0>;
+ clock-names = "vpu_intr",
+ "hdmi_intr_sync",
+ "venci_int",
+ "tmds",
+ "hdmi_tx_pixel",
+ "cts_encp",
+ "cts_enci",
+ "cts_enct",
+ "cts_encl",
+ "cts_vdac0";
+
+ resets = <&clkc CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE>,
+ <&clkc CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST>,
+ <&clkc CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE>,
+ <&clkc CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST>;
+ reset-names = "vid_pll_pre",
+ "vid_pll_post",
+ "vid_pll_soft_pre",
+ "vid_pll_soft_post";
+
+ phys = <&cvbs_dac>;
+ phy-names = "cvbs-dac";
+
+ power-domains = <&pwrc PWRC_MESON8_VPU_ID>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CVBS VDAC output port */
+ cvbs_vdac_port: port@0 {
+ reg = <0>;
+ };
+ };
};
}; /* end of / */
@@ -389,6 +454,8 @@ &ao_arc_rproc {
sram = <&ao_arc_sram>;
resets = <&reset RESET_MEDIA_CPU>;
clocks = <&clkc CLKID_AO_MEDIA_CPU>;
+ status = "okay";
+ firmware-name = "zephyr.elf";
};
&cbus {
@@ -547,6 +614,16 @@ smp-sram@1ff80 {
};
};
+&cvbs_dac {
+ compatible = "amlogic,meson8b-cvbs-dac", "amlogic,meson-cvbs-dac";
+
+ clocks = <&clkc CLKID_CTS_VDAC0>;
+
+ nvmem-cells = <&cvbs_trimming>;
+ nvmem-cell-names = "cvbs_trimming";
+
+ status = "okay";
+};
&efuse {
compatible = "amlogic,meson8b-efuse";
@@ -557,6 +634,10 @@ temperature_calib: calib@1f4 {
/* only the upper two bytes are relevant */
reg = <0x1f4 0x4>;
};
+
+ cvbs_trimming: calib@1f8 {
+ reg = <0x1f8 0x2>;
+ };
};
&ethmac {
diff --git a/arch/arm/boot/dts/amlogic/meson8m2.dtsi b/arch/arm/boot/dts/amlogic/meson8m2.dtsi
index 6725dd9fd..fcb2ad976 100644
--- a/arch/arm/boot/dts/amlogic/meson8m2.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8m2.dtsi
@@ -96,6 +96,10 @@ &usb1_phy {
compatible = "amlogic,meson8m2-usb2-phy", "amlogic,meson-mx-usb2-phy";
};
+&vpu {
+ compatible = "amlogic,meson8m2-vpu";
+};
+
&wdt {
compatible = "amlogic,meson8m2-wdt", "amlogic,meson8b-wdt";
};
--
2.45.1

View File

@@ -0,0 +1,125 @@
From d724d428a4f5d92bf2b5f169f948e698549b4386 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 5 May 2019 02:30:11 +0200
Subject: [PATCH 60/96] ARM: dts: meson8: add the HDMI controller - WiP
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8.dtsi | 67 ++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index 519443e19..f63ac1404 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -315,6 +315,39 @@ mali: gpu@c0000 {
#cooling-cells = <2>; /* min followed by max */
};
+ hdmi_tx: hdmi-tx@42000 {
+ compatible = "amlogic,meson8-hdmi-tx";
+ reg = <0x42000 0xc>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+ phys = <&hdmi_tx_phy>;
+ phy-names = "hdmi";
+ clocks = <&clkc CLKID_HDMI_PCLK>,
+ <&clkc CLKID_HDMI_SYS>;
+ clock-names = "pclk", "sys";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ #sound-dai-cells = <1>;
+ sound-name-prefix = "HDMITX";
+
+ status = "disabled";
+
+ /* VPU VENC Input */
+ hdmi_tx_venc_port: port@0 {
+ reg = <0>;
+
+ hdmi_tx_in: endpoint {
+ remote-endpoint = <&hdmi_tx_out>;
+ };
+ };
+
+ /* TMDS Output */
+ hdmi_tx_tmds_port: port@1 {
+ reg = <1>;
+ };
+ };
+
vpu: vpu@100000 {
compatible = "amlogic,meson8-vpu";
@@ -378,6 +411,15 @@ vpu: vpu@100000 {
cvbs_vdac_port: port@0 {
reg = <0>;
};
+
+ /* HDMI-TX output port */
+ hdmi_tx_port: port@1 {
+ reg = <1>;
+
+ hdmi_tx_out: endpoint {
+ remote-endpoint = <&hdmi_tx_in>;
+ };
+ };
};
};
}; /* end of / */
@@ -544,11 +586,26 @@ gpio: banks@80b0 {
gpio-ranges = <&pinctrl_cbus 0 0 120>;
};
+ hdmi_hpd_pins: hdmi-hpd {
+ mux {
+ groups = "hdmi_hpd";
+ function = "hdmi";
+ bias-disable;
+ };
+ };
+
+ hdmi_i2c_pins: hdmi-i2c {
+ mux {
+ groups = "hdmi_sda", "hdmi_scl";
+ function = "hdmi";
+ bias-disable;
+ };
+ };
+
pwm_c_dv9_pins: pwm-c-dv9 {
mux {
groups = "pwm_c_dv9";
function = "pwm_c";
- bias-disable;
};
};
@@ -556,7 +613,6 @@ pwm_d_pins: pwm-d {
mux {
groups = "pwm_d";
function = "pwm_d";
- bias-disable;
};
};
@@ -740,6 +796,13 @@ pwrc: power-controller@100 {
assigned-clocks = <&clkc CLKID_VPU>;
assigned-clock-rates = <364285714>;
};
+
+ hdmi_tx_phy: hdmi-phy@3a0 {
+ compatible = "amlogic,meson8-hdmi-tx-phy";
+ clocks = <&clkc CLKID_HDMI_PLL_HDMI_OUT>;
+ reg = <0x3a0 0xc>;
+ #phy-cells = <0>;
+ };
};
&hwrng {
--
2.45.1

View File

@@ -0,0 +1,36 @@
From 1b8ef484e7a3af4367b771e74c8f72e8326f897f Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 4 Jun 2021 21:50:06 +0200
Subject: [PATCH 61/96] ARM: dts: meson8: Add the shared CMA dma memory pool
The 4K HDMI modes needs more CMA memory (than the default 64MiB) to be
reserved at boot-time. Add a shared-dma-pool with increased size so the
4K HDMI modes can be used.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index f63ac1404..de9845433 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -193,6 +193,14 @@ power-firmware@4f00000 {
reg = <0x4f00000 0x100000>;
no-map;
};
+
+ linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0x10000000>;
+ alignment = <0x400000>;
+ linux,cma-default;
+ };
};
thermal-zones {
--
2.45.1

View File

@@ -0,0 +1,50 @@
From 4d4c55a553ee723670f756737589633fc95894f2 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 5 May 2019 11:44:08 +0200
Subject: [PATCH 62/96] ARM: dts: meson8: add the AO CEC controller - WiP
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8.dtsi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson8.dtsi b/arch/arm/boot/dts/amlogic/meson8.dtsi
index de9845433..ae1047eca 100644
--- a/arch/arm/boot/dts/amlogic/meson8.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8.dtsi
@@ -478,6 +478,14 @@ gpio_ao: ao-bank@14 {
gpio-ranges = <&pinctrl_aobus 0 0 16>;
};
+ hdmi_cec_ao_pins: hdmi-cec-ao {
+ mux {
+ groups = "hdmi_cec_ao";
+ function = "hdmi_cec_ao";
+ bias-pull-up;
+ };
+ };
+
i2s_am_clk_pins: i2s-am-clk-out {
mux {
groups = "i2s_am_clk_out_ao";
@@ -542,6 +550,15 @@ mux {
};
};
};
+
+ cec_AO: cec@100 {
+ compatible = "amlogic,meson-gx-ao-cec"; // FIXME
+ reg = <0x100 0x14>;
+ interrupts = <GIC_SPI 151 IRQ_TYPE_EDGE_RISING>;
+ // TODO: 32768HZ clock
+ hdmi-phandle = <&hdmi_tx>;
+ status = "disabled";
+ };
};
&ao_arc_rproc {
--
2.45.1

View File

@@ -0,0 +1,120 @@
From 15091212cb8b362780e0c54ae0e430bfeca46525 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 5 May 2019 02:30:29 +0200
Subject: [PATCH 63/96] ARM: dts: meson8b: add the HDMI controller - WiP
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8b.dtsi | 69 ++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi
index 87aa74675..176b2dc71 100644
--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi
@@ -277,6 +277,39 @@ mali: gpu@c0000 {
#cooling-cells = <2>; /* min followed by max */
};
+ hdmi_tx: hdmi-tx@42000 {
+ compatible = "amlogic,meson8b-hdmi-tx";
+ reg = <0x42000 0xc>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+ phys = <&hdmi_tx_phy>;
+ phy-names = "hdmi";
+ clocks = <&clkc CLKID_HDMI_PCLK>,
+ <&clkc CLKID_HDMI_SYS>;
+ clock-names = "pclk", "sys";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ #sound-dai-cells = <1>;
+ sound-name-prefix = "HDMITX";
+
+ status = "disabled";
+
+ /* VPU VENC Input */
+ hdmi_tx_venc_port: port@0 {
+ reg = <0>;
+
+ hdmi_tx_in: endpoint {
+ remote-endpoint = <&hdmi_tx_out>;
+ };
+ };
+
+ /* TMDS Output */
+ hdmi_tx_tmds_port: port@1 {
+ reg = <1>;
+ };
+ };
+
vpu: vpu@100000 {
compatible = "amlogic,meson8b-vpu";
@@ -336,10 +369,22 @@ vpu: vpu@100000 {
#address-cells = <1>;
#size-cells = <0>;
+ #sound-dai-cells = <0>;
+ sound-name-prefix = "HDMITX";
+
/* CVBS VDAC output port */
cvbs_vdac_port: port@0 {
reg = <0>;
};
+
+ /* HDMI-TX output port */
+ hdmi_tx_port: port@1 {
+ reg = <1>;
+
+ hdmi_tx_out: endpoint {
+ remote-endpoint = <&hdmi_tx_in>;
+ };
+ };
};
};
}; /* end of / */
@@ -538,6 +583,22 @@ mux {
};
};
+ hdmi_hpd_pins: hdmi-hpd {
+ mux {
+ groups = "hdmi_hpd";
+ function = "hdmi";
+ bias-disable;
+ };
+ };
+
+ hdmi_i2c_pins: hdmi-i2c {
+ mux {
+ groups = "hdmi_sda", "hdmi_scl";
+ function = "hdmi";
+ bias-disable;
+ };
+ };
+
i2c_a_pins: i2c-a {
mux {
groups = "i2c_sda_a", "i2c_sck_a";
@@ -700,6 +761,14 @@ pwrc: power-controller@100 {
assigned-clocks = <&clkc CLKID_VPU>;
assigned-clock-rates = <182142857>;
};
+
+ hdmi_tx_phy: hdmi-phy@3a0 {
+ compatible = "amlogic,meson8b-hdmi-tx-phy",
+ "amlogic,meson8-hdmi-tx-phy";
+ clocks = <&clkc CLKID_HDMI_PLL_HDMI_OUT>;
+ reg = <0x3a0 0xc>;
+ #phy-cells = <0>;
+ };
};
&hwrng {
--
2.45.1

View File

@@ -0,0 +1,50 @@
From 6b21e706b95e5e0c8c5b9f691f2fc64befdf8d08 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sun, 5 May 2019 11:44:20 +0200
Subject: [PATCH 64/96] ARM: dts: meson8b: add the AO CEC controller - WiP
WiP
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
arch/arm/boot/dts/amlogic/meson8b.dtsi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi
index 176b2dc71..3e5d97e0c 100644
--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi
+++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi
@@ -435,6 +435,14 @@ gpio_ao: ao-bank@14 {
gpio-ranges = <&pinctrl_aobus 0 0 16>;
};
+ hdmi_cec_ao_pins: hdmi-cec-ao {
+ mux {
+ groups = "hdmi_cec_1";
+ function = "hdmi_cec";
+ bias-pull-up;
+ };
+ };
+
i2s_am_clk_pins: i2s-am-clk-out {
mux {
groups = "i2s_am_clk_out";
@@ -491,6 +499,15 @@ mux {
};
};
};
+
+ cec_AO: cec@100 {
+ compatible = "amlogic,meson-gx-ao-cec"; // FIXME
+ reg = <0x100 0x14>;
+ interrupts = <GIC_SPI 151 IRQ_TYPE_EDGE_RISING>;
+ // TODO: 32768HZ clock
+ hdmi-phandle = <&hdmi_tx>;
+ status = "disabled";
+ };
};
&ao_arc_rproc {
--
2.45.1

View File

@@ -1,7 +1,7 @@
From e9d0d7bb75ff8234d717fb640c020ffe303a8d11 Mon Sep 17 00:00:00 2001
From 9d61f99a90171d451718e0afb254d5733c4b4852 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Fri, 20 Mar 2020 15:17:51 +0100
Subject: [PATCH] ARM: dts: meson8b: odroid-c1: enable HDMI for the
Subject: [PATCH 66/96] ARM: dts: meson8b: odroid-c1: enable HDMI for the
Odroid-C1 - WiP
WiP
@@ -12,7 +12,7 @@ Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
1 file changed, 59 insertions(+)
diff --git a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts
index 94168284..7e43212e 100644
index eaf89638c..b03273d90 100644
--- a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts
+++ b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts
@@ -32,6 +32,17 @@ emmc_pwrseq: emmc-pwrseq {
@@ -69,10 +69,10 @@ index 94168284..7e43212e 100644
+ };
+ };
+
vcc_1v8: regulator-vcc-1v8 {
/*
* RICHTEK RT9179 configured for a fixed output voltage of
@@ -187,6 +230,10 @@ vdd_rtc: regulator-vdd-rtc {
usb0_vbus: regulator-usb0-vbus {
/* Richtek RT9715EGB */
compatible = "regulator-fixed";
@@ -201,6 +244,10 @@ vdd_rtc: regulator-vdd-rtc {
};
};
@@ -83,7 +83,7 @@ index 94168284..7e43212e 100644
&cpu0 {
cpu-supply = <&vcck>;
};
@@ -283,6 +330,18 @@ &gpio_ao {
@@ -297,6 +344,18 @@ &gpio_ao {
"SYS_LED", "", "";
};
@@ -103,5 +103,5 @@ index 94168284..7e43212e 100644
status = "okay";
pinctrl-0 = <&ir_recv_pins>;
--
2.34.1
2.45.1

View File

@@ -1,27 +0,0 @@
From d11b44bf44111b9f1d5497e92826df46ff065dbd Mon Sep 17 00:00:00 2001
From: hzy <hzyitc@outlook.com>
Date: Sat, 18 Nov 2023 01:22:03 +0800
Subject: [PATCH 2/3] meson8/meson8b/meson8m2: drm: Forcefully enable XRGB
format
Signed-off-by: hzy <hzyitc@outlook.com>
---
drivers/gpu/drm/meson/meson_plane.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
index 27e39577..027b2fe7 100644
--- a/drivers/gpu/drm/meson/meson_plane.c
+++ b/drivers/gpu/drm/meson/meson_plane.c
@@ -483,6 +483,8 @@ static const struct drm_plane_funcs meson_plane_funcs = {
static const uint32_t supported_drm_formats_m8[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
DRM_FORMAT_RGB888,
DRM_FORMAT_RGB565,
};
--
2.34.1

View File

@@ -1,26 +0,0 @@
From 99a889c050d71d663aba1ba2a706348be72ca787 Mon Sep 17 00:00:00 2001
From: hzy <hzyitc@outlook.com>
Date: Fri, 17 Nov 2023 22:54:18 +0800
Subject: [PATCH 3/3] drm/meson: Support meson{8,8b}-hdmi-tx components
Signed-off-by: hzy <hzyitc@outlook.com>
---
drivers/gpu/drm/meson/meson_drv.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index e8134e4c..c3e8fef9 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -668,6 +668,8 @@ static void meson_drv_shutdown(struct platform_device *pdev)
* private structure for HHI registers.
*/
static const struct of_device_id components_dev_match[] = {
+ { .compatible = "amlogic,meson8-hdmi-tx" },
+ { .compatible = "amlogic,meson8b-hdmi-tx" },
{ .compatible = "amlogic,meson-gxbb-dw-hdmi" },
{ .compatible = "amlogic,meson-gxl-dw-hdmi" },
{ .compatible = "amlogic,meson-gxm-dw-hdmi" },
--
2.34.1