diff --git a/config/sources/families/include/meson_common.inc b/config/sources/families/include/meson_common.inc index cef6e2c6f5d4..955c07cfe223 100644 --- a/config/sources/families/include/meson_common.inc +++ b/config/sources/families/include/meson_common.inc @@ -32,7 +32,7 @@ case $BRANCH in ;; edge) - declare -g KERNEL_MAJOR_MINOR="6.10" + declare -g KERNEL_MAJOR_MINOR="6.13" ;; esac diff --git a/patch/kernel/archive/meson-6.13/0006-ARM-dts-amlogic-meson8b-switch-to-the-new-PWM-contro.patch b/patch/kernel/archive/meson-6.13/0006-ARM-dts-amlogic-meson8b-switch-to-the-new-PWM-contro.patch new file mode 100644 index 000000000000..155ec7736cba --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0006-ARM-dts-amlogic-meson8b-switch-to-the-new-PWM-contro.patch @@ -0,0 +1,100 @@ +From 66e028c9df703d27af0b532b72278a558af19ddb Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 25 Dec 2024 12:16:38 +0100 +Subject: [PATCH 006/126] ARM: dts: amlogic: meson8b: switch to the new PWM + controller binding + +Use the new PWM controller binding which now relies on passing all +clock inputs available on the SoC (instead of passing the "wanted" +clock input for a given board). + +Signed-off-by: Martin Blumenstingl +--- + arch/arm/boot/dts/amlogic/meson8b-ec100.dts | 2 -- + arch/arm/boot/dts/amlogic/meson8b-mxq.dts | 2 -- + arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts | 2 -- + arch/arm/boot/dts/amlogic/meson8b.dtsi | 18 +++++++++++++++--- + 4 files changed, 15 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/boot/dts/amlogic/meson8b-ec100.dts b/arch/arm/boot/dts/amlogic/meson8b-ec100.dts +index 18ea6592b..236999548 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b-ec100.dts ++++ b/arch/arm/boot/dts/amlogic/meson8b-ec100.dts +@@ -443,8 +443,6 @@ &pwm_cd { + status = "okay"; + pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; + pinctrl-names = "default"; +- clocks = <&xtal>, <&xtal>; +- clock-names = "clkin0", "clkin1"; + }; + + &rtc { +diff --git a/arch/arm/boot/dts/amlogic/meson8b-mxq.dts b/arch/arm/boot/dts/amlogic/meson8b-mxq.dts +index fb28cb330..0bca0b33e 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b-mxq.dts ++++ b/arch/arm/boot/dts/amlogic/meson8b-mxq.dts +@@ -162,8 +162,6 @@ &pwm_cd { + status = "okay"; + pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; + pinctrl-names = "default"; +- clocks = <&xtal>, <&xtal>; +- clock-names = "clkin0", "clkin1"; + }; + + &uart_AO { +diff --git a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts +index 2aa012f38..1cd209320 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts ++++ b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts +@@ -347,8 +347,6 @@ &pwm_cd { + status = "okay"; + pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; + pinctrl-names = "default"; +- clocks = <&xtal>, <&xtal>; +- clock-names = "clkin0", "clkin1"; + }; + + &rtc { +diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi +index 9e02a97f8..0876611ce 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi +@@ -403,8 +403,12 @@ analog_top: analog-top@81a8 { + }; + + pwm_ef: pwm@86c0 { +- compatible = "amlogic,meson8b-pwm"; ++ compatible = "amlogic,meson8b-pwm-v2", "amlogic,meson8-pwm-v2"; + reg = <0x86c0 0x10>; ++ clocks = <&xtal>, ++ <>, /* unknown/untested, the datasheet calls it "Video PLL" */ ++ <&clkc CLKID_FCLK_DIV4>, ++ <&clkc CLKID_FCLK_DIV3>; + #pwm-cells = <3>; + status = "disabled"; + }; +@@ -674,11 +678,19 @@ timer@600 { + }; + + &pwm_ab { +- compatible = "amlogic,meson8b-pwm"; ++ compatible = "amlogic,meson8b-pwm-v2", "amlogic,meson8-pwm-v2"; ++ clocks = <&xtal>, ++ <>, /* unknown/untested, the datasheet calls it "Video PLL" */ ++ <&clkc CLKID_FCLK_DIV4>, ++ <&clkc CLKID_FCLK_DIV3>; + }; + + &pwm_cd { +- compatible = "amlogic,meson8b-pwm"; ++ compatible = "amlogic,meson8b-pwm-v2", "amlogic,meson8-pwm-v2"; ++ clocks = <&xtal>, ++ <>, /* unknown/untested, the datasheet calls it "Video PLL" */ ++ <&clkc CLKID_FCLK_DIV4>, ++ <&clkc CLKID_FCLK_DIV3>; + }; + + &rtc { +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0016-drm-connector-add-mutex-to-protect-ELD-from-concurre.patch b/patch/kernel/archive/meson-6.13/0016-drm-connector-add-mutex-to-protect-ELD-from-concurre.patch new file mode 100644 index 000000000000..eceeb492f921 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0016-drm-connector-add-mutex-to-protect-ELD-from-concurre.patch @@ -0,0 +1,86 @@ +From 250f94fef62c8315df28aa7220c32f8e88e35c02 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Fri, 6 Dec 2024 11:43:04 +0200 +Subject: [PATCH 016/126] drm/connector: add mutex to protect ELD from + concurrent access + +The connector->eld is accessed by the .get_eld() callback. This access +can collide with the drm_edid_to_eld() updating the data at the same +time. Add drm_connector.eld_mutex to protect the data from concurrenct +access. Individual drivers are not updated (to reduce possible issues +while applying the patch), maintainers are to find a best suitable way +to lock that mutex while accessing the ELD data. + +Reviewed-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241206-drm-connector-eld-mutex-v2-1-c9bce1ee8bea@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/drm_connector.c | 1 + + drivers/gpu/drm/drm_edid.c | 6 ++++++ + include/drm/drm_connector.h | 5 ++++- + 3 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index fc35f47e2..bbdaaf702 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -277,6 +277,7 @@ static int __drm_connector_init(struct drm_device *dev, + INIT_LIST_HEAD(&connector->probed_modes); + INIT_LIST_HEAD(&connector->modes); + mutex_init(&connector->mutex); ++ mutex_init(&connector->eld_mutex); + mutex_init(&connector->edid_override_mutex); + mutex_init(&connector->hdmi.infoframes.lock); + connector->edid_blob_ptr = NULL; +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 855beafb7..13bc4c290 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -5605,7 +5605,9 @@ EXPORT_SYMBOL(drm_edid_get_monitor_name); + + static void clear_eld(struct drm_connector *connector) + { ++ mutex_lock(&connector->eld_mutex); + memset(connector->eld, 0, sizeof(connector->eld)); ++ mutex_unlock(&connector->eld_mutex); + + connector->latency_present[0] = false; + connector->latency_present[1] = false; +@@ -5657,6 +5659,8 @@ static void drm_edid_to_eld(struct drm_connector *connector, + if (!drm_edid) + return; + ++ mutex_lock(&connector->eld_mutex); ++ + mnl = get_monitor_name(drm_edid, &eld[DRM_ELD_MONITOR_NAME_STRING]); + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD monitor %s\n", + connector->base.id, connector->name, +@@ -5717,6 +5721,8 @@ static void drm_edid_to_eld(struct drm_connector *connector, + drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] ELD size %d, SAD count %d\n", + connector->base.id, connector->name, + drm_eld_size(eld), total_sad_count); ++ ++ mutex_unlock(&connector->eld_mutex); + } + + static int _drm_edid_to_sad(const struct drm_edid *drm_edid, +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index e3fa43291..1e2b25e20 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -2001,8 +2001,11 @@ struct drm_connector { + struct drm_encoder *encoder; + + #define MAX_ELD_BYTES 128 +- /** @eld: EDID-like data, if present */ ++ /** @eld: EDID-like data, if present, protected by @eld_mutex */ + uint8_t eld[MAX_ELD_BYTES]; ++ /** @eld_mutex: protection for concurrenct access to @eld */ ++ struct mutex eld_mutex; ++ + /** @latency_present: AV delay info from ELD, if found */ + bool latency_present[2]; + /** +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0017-drm-connector-Add-a-way-to-init-add-a-connector-in-s.patch b/patch/kernel/archive/meson-6.13/0017-drm-connector-Add-a-way-to-init-add-a-connector-in-s.patch new file mode 100644 index 000000000000..933f6b1e6375 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0017-drm-connector-Add-a-way-to-init-add-a-connector-in-s.patch @@ -0,0 +1,318 @@ +From 44e7414f28f4f8cfaca7935bbe96a4e10d78db7f Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Thu, 12 Dec 2024 01:03:18 +0200 +Subject: [PATCH 017/126] drm/connector: Add a way to init/add a connector in + separate steps + +Atm when the connector is added to the drm_mode_config::connector_list, +the connector may not be fully initialized yet. This is not a problem +for static connectors initialized/added during driver loading, for which +the driver ensures that look-ups via the above list are not possible +until all the connector and other required state is fully initialized +already. It's also not a problem for user space looking up either a +static or dynamic (see what this is below) connector, since this will be +only possible once the connector is registered. + +A dynamic - atm only a DP MST - connector can be initialized and added +after the load time initialization is done. Such a connector may be +looked up by in-kernel users once it's added to the connector list. In +particular a hotplug handler could perform a detection on all the +connectors on the list and hence find a connector there which isn't yet +initialized. For instance the connector's helper hooks may be unset, +leading to a NULL dereference while the detect helper calls the +connector's drm_connector_helper_funcs::detect() or detect_ctx() +handler. + +To resolve the above issue, add a way for dynamic connectors to +separately initialize the DRM core specific parts of the connector +without adding it to the connector list - by calling the new +drm_connector_dynamic_init() - and to add the connector to the list +later once all the initialization is complete and the connector is +registered - by calling the new drm_connector_dynamic_register(). + +Adding the above 2 functions was also motivated to make the distinction +of the interface between static and dynamic connectors clearer: Drivers +should manually initialize and register only dynamic connectors (with +the above 2 functions). A driver should only initialize a static +connector (with one of the drm_connector_init*, drmm_connector_init* +functions) while the registration of the connector will be done +automatically by DRM core. + +v2: (Jani) +- Let initing DDC as well via drm_connector_init_core(). +- Rename __drm_connector_init to drm_connector_init_core_and_add(). + +v3: +- Rename drm_connector_init_core() to drm_connector_dynamic_init(). + (Sima) +- Instead of exporting drm_connector_add(), move adding the connector + to the registration step via a new drm_connector_dynamic_register(). + (Sima) +- Update drm_connector_dynamic_init()'s function documentation and the + commit log according to the above changes. +- Update the commit log describing the problematic scenario during + connector detection. (Maxime) + +Cc: Jani Nikula +Cc: Simona Vetter +Cc: Maxime Ripard +Reviewed-by: Rodrigo Vivi (v1) +Reviewed-by: Lyude Paul +Reviewed-by: Jani Nikula +Reviewed-by: Maxime Ripard +Acked-by: Alex Deucher +Acked-by: Wayne Lin +Signed-off-by: Imre Deak +Link: https://patchwork.freedesktop.org/patch/msgid/20241211230328.4012496-2-imre.deak@intel.com +--- + drivers/gpu/drm/drm_connector.c | 150 +++++++++++++++++++++++++++----- + include/drm/drm_connector.h | 6 ++ + 2 files changed, 136 insertions(+), 20 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index bbdaaf702..464b2f583 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -218,11 +218,11 @@ void drm_connector_free_work_fn(struct work_struct *work) + } + } + +-static int __drm_connector_init(struct drm_device *dev, +- struct drm_connector *connector, +- const struct drm_connector_funcs *funcs, +- int connector_type, +- struct i2c_adapter *ddc) ++static int drm_connector_init_only(struct drm_device *dev, ++ struct drm_connector *connector, ++ const struct drm_connector_funcs *funcs, ++ int connector_type, ++ struct i2c_adapter *ddc) + { + struct drm_mode_config *config = &dev->mode_config; + int ret; +@@ -273,6 +273,7 @@ static int __drm_connector_init(struct drm_device *dev, + /* provide ddc symlink in sysfs */ + connector->ddc = ddc; + ++ INIT_LIST_HEAD(&connector->head); + INIT_LIST_HEAD(&connector->global_connector_list_entry); + INIT_LIST_HEAD(&connector->probed_modes); + INIT_LIST_HEAD(&connector->modes); +@@ -289,14 +290,6 @@ static int __drm_connector_init(struct drm_device *dev, + + drm_connector_get_cmdline_mode(connector); + +- /* We should add connectors at the end to avoid upsetting the connector +- * index too much. +- */ +- spin_lock_irq(&config->connector_list_lock); +- list_add_tail(&connector->head, &config->connector_list); +- config->num_connector++; +- spin_unlock_irq(&config->connector_list_lock); +- + if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL && + connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + drm_connector_attach_edid_property(connector); +@@ -333,6 +326,58 @@ static int __drm_connector_init(struct drm_device *dev, + return ret; + } + ++static void drm_connector_add(struct drm_connector *connector) ++{ ++ struct drm_device *dev = connector->dev; ++ struct drm_mode_config *config = &dev->mode_config; ++ ++ /* ++ * TODO: Change this to a WARN, once all drivers are converted to ++ * call drm_connector_dynamic_init() for MST connectors. ++ */ ++ if (!list_empty(&connector->head)) ++ return; ++ ++ spin_lock_irq(&config->connector_list_lock); ++ list_add_tail(&connector->head, &config->connector_list); ++ config->num_connector++; ++ spin_unlock_irq(&config->connector_list_lock); ++} ++ ++static void drm_connector_remove(struct drm_connector *connector) ++{ ++ struct drm_device *dev = connector->dev; ++ ++ /* ++ * For dynamic connectors drm_connector_cleanup() can call this function ++ * before the connector is registered and added to the list. ++ */ ++ if (list_empty(&connector->head)) ++ return; ++ ++ spin_lock_irq(&dev->mode_config.connector_list_lock); ++ list_del_init(&connector->head); ++ dev->mode_config.num_connector--; ++ spin_unlock_irq(&dev->mode_config.connector_list_lock); ++} ++ ++static int drm_connector_init_and_add(struct drm_device *dev, ++ struct drm_connector *connector, ++ const struct drm_connector_funcs *funcs, ++ int connector_type, ++ struct i2c_adapter *ddc) ++{ ++ int ret; ++ ++ ret = drm_connector_init_only(dev, connector, funcs, connector_type, ddc); ++ if (ret) ++ return ret; ++ ++ drm_connector_add(connector); ++ ++ return 0; ++} ++ + /** + * drm_connector_init - Init a preallocated connector + * @dev: DRM device +@@ -362,10 +407,51 @@ int drm_connector_init(struct drm_device *dev, + if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) + return -EINVAL; + +- return __drm_connector_init(dev, connector, funcs, connector_type, NULL); ++ return drm_connector_init_and_add(dev, connector, funcs, connector_type, NULL); + } + EXPORT_SYMBOL(drm_connector_init); + ++/** ++ * drm_connector_dynamic_init - Init a preallocated dynamic connector ++ * @dev: DRM device ++ * @connector: the connector to init ++ * @funcs: callbacks for this connector ++ * @connector_type: user visible type of the connector ++ * @ddc: pointer to the associated ddc adapter ++ * ++ * Initialises a preallocated dynamic connector. Connectors should be ++ * subclassed as part of driver connector objects. The connector ++ * structure should not be allocated with devm_kzalloc(). ++ * ++ * Drivers should call this for dynamic connectors which can be hotplugged ++ * after drm_dev_register() has been called already, e.g. DP MST connectors. ++ * For all other - static - connectors, drivers should call one of the ++ * drm_connector_init*()/drmm_connector_init*() functions. ++ * ++ * After calling this function the drivers must call ++ * drm_connector_dynamic_register(). ++ * ++ * To remove the connector the driver must call drm_connector_unregister() ++ * followed by drm_connector_put(). Putting the last reference will call the ++ * driver's &drm_connector_funcs.destroy hook, which in turn must call ++ * drm_connector_cleanup() and free the connector structure. ++ * ++ * Returns: ++ * Zero on success, error code on failure. ++ */ ++int drm_connector_dynamic_init(struct drm_device *dev, ++ struct drm_connector *connector, ++ const struct drm_connector_funcs *funcs, ++ int connector_type, ++ struct i2c_adapter *ddc) ++{ ++ if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) ++ return -EINVAL; ++ ++ return drm_connector_init_only(dev, connector, funcs, connector_type, ddc); ++} ++EXPORT_SYMBOL(drm_connector_dynamic_init); ++ + /** + * drm_connector_init_with_ddc - Init a preallocated connector + * @dev: DRM device +@@ -399,7 +485,7 @@ int drm_connector_init_with_ddc(struct drm_device *dev, + if (drm_WARN_ON(dev, !(funcs && funcs->destroy))) + return -EINVAL; + +- return __drm_connector_init(dev, connector, funcs, connector_type, ddc); ++ return drm_connector_init_and_add(dev, connector, funcs, connector_type, ddc); + } + EXPORT_SYMBOL(drm_connector_init_with_ddc); + +@@ -443,7 +529,7 @@ int drmm_connector_init(struct drm_device *dev, + if (drm_WARN_ON(dev, funcs && funcs->destroy)) + return -EINVAL; + +- ret = __drm_connector_init(dev, connector, funcs, connector_type, ddc); ++ ret = drm_connector_init_and_add(dev, connector, funcs, connector_type, ddc); + if (ret) + return ret; + +@@ -660,10 +746,8 @@ void drm_connector_cleanup(struct drm_connector *connector) + connector->name = NULL; + fwnode_handle_put(connector->fwnode); + connector->fwnode = NULL; +- spin_lock_irq(&dev->mode_config.connector_list_lock); +- list_del(&connector->head); +- dev->mode_config.num_connector--; +- spin_unlock_irq(&dev->mode_config.connector_list_lock); ++ ++ drm_connector_remove(connector); + + WARN_ON(connector->state && !connector->funcs->atomic_destroy_state); + if (connector->state && connector->funcs->atomic_destroy_state) +@@ -750,6 +834,32 @@ int drm_connector_register(struct drm_connector *connector) + } + EXPORT_SYMBOL(drm_connector_register); + ++/** ++ * drm_connector_dynamic_register - register a dynamic connector ++ * @connector: the connector to register ++ * ++ * Register userspace interfaces for a connector. Only call this for connectors ++ * initialized by calling drm_connector_dynamic_init(). All other connectors ++ * will be registered automatically when calling drm_dev_register(). ++ * ++ * When the connector is no longer available the driver must call ++ * drm_connector_unregister(). ++ * ++ * Returns: ++ * Zero on success, error code on failure. ++ */ ++int drm_connector_dynamic_register(struct drm_connector *connector) ++{ ++ /* Was the connector inited already? */ ++ if (WARN_ON(!(connector->funcs && connector->funcs->destroy))) ++ return -EINVAL; ++ ++ drm_connector_add(connector); ++ ++ return drm_connector_register(connector); ++} ++EXPORT_SYMBOL(drm_connector_dynamic_register); ++ + /** + * drm_connector_unregister - unregister a connector + * @connector: the connector to unregister +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index 1e2b25e20..d1be19242 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -2129,6 +2129,11 @@ int drm_connector_init(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, + int connector_type); ++int drm_connector_dynamic_init(struct drm_device *dev, ++ struct drm_connector *connector, ++ const struct drm_connector_funcs *funcs, ++ int connector_type, ++ struct i2c_adapter *ddc); + int drm_connector_init_with_ddc(struct drm_device *dev, + struct drm_connector *connector, + const struct drm_connector_funcs *funcs, +@@ -2150,6 +2155,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev, + unsigned int max_bpc); + void drm_connector_attach_edid_property(struct drm_connector *connector); + int drm_connector_register(struct drm_connector *connector); ++int drm_connector_dynamic_register(struct drm_connector *connector); + void drm_connector_unregister(struct drm_connector *connector); + int drm_connector_attach_encoder(struct drm_connector *connector, + struct drm_encoder *encoder); +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0018-drm-connector-Add-deprecation-notes-for-drm_connecto.patch b/patch/kernel/archive/meson-6.13/0018-drm-connector-Add-deprecation-notes-for-drm_connecto.patch new file mode 100644 index 000000000000..58f76305de7e --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0018-drm-connector-Add-deprecation-notes-for-drm_connecto.patch @@ -0,0 +1,73 @@ +From 2f91cf27a10f213e65998bd71e1b164be6e2ec66 Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Thu, 12 Dec 2024 01:03:20 +0200 +Subject: [PATCH 018/126] drm/connector: Add deprecation notes for + drm_connector_register/unregister + +Drivers should register/unregister only dynamic (MST) connectors +manually using drm_connector_dynamic_register()/unregister(). +Static connectors are registered/unregistered by the DRM core +automatically. Some drivers still call drm_connector_register()/ +unregister() for static connectors, both of which should be a nop +for them and hence are scheduled to be removed. Update the function +documentation for these functions accordingly. + +v2: s/deprication/deprecation in subject line. (Jani) + +Reviewed-by: Lyude Paul +Reviewed-by: Jani Nikula +Acked-by: Alex Deucher +Acked-by: Wayne Lin +Signed-off-by: Imre Deak +Link: https://patchwork.freedesktop.org/patch/msgid/20241211230328.4012496-4-imre.deak@intel.com +--- + drivers/gpu/drm/drm_connector.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index 464b2f583..3c6c0d7b9 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -768,14 +768,17 @@ EXPORT_SYMBOL(drm_connector_cleanup); + * drm_connector_register - register a connector + * @connector: the connector to register + * +- * Register userspace interfaces for a connector. Only call this for connectors +- * which can be hotplugged after drm_dev_register() has been called already, +- * e.g. DP MST connectors. All other connectors will be registered automatically +- * when calling drm_dev_register(). ++ * Register userspace interfaces for a connector. Drivers shouldn't call this ++ * function. Static connectors will be registered automatically by DRM core ++ * from drm_dev_register(), dynamic connectors (MST) should be registered by ++ * drivers calling drm_connector_dynamic_register(). + * + * When the connector is no longer available, callers must call + * drm_connector_unregister(). + * ++ * Note: Existing uses of this function in drivers should be a nop already and ++ * are scheduled to be removed. ++ * + * Returns: + * Zero on success, error code on failure. + */ +@@ -864,9 +867,14 @@ EXPORT_SYMBOL(drm_connector_dynamic_register); + * drm_connector_unregister - unregister a connector + * @connector: the connector to unregister + * +- * Unregister userspace interfaces for a connector. Only call this for +- * connectors which have been registered explicitly by calling +- * drm_connector_register(). ++ * Unregister userspace interfaces for a connector. Drivers should call this ++ * for dynamic connectors (MST) only, which were registered explicitly by ++ * calling drm_connector_dynamic_register(). All other - static - connectors ++ * will be unregistered automatically by DRM core and drivers shouldn't call ++ * this function for those. ++ * ++ * Note: Existing uses of this function in drivers for static connectors ++ * should be a nop already and are scheduled to be removed. + */ + void drm_connector_unregister(struct drm_connector *connector) + { +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0019-drm-connector-Warn-if-a-connector-is-registered-adde.patch b/patch/kernel/archive/meson-6.13/0019-drm-connector-Warn-if-a-connector-is-registered-adde.patch new file mode 100644 index 000000000000..0d1a6a5f78bc --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0019-drm-connector-Warn-if-a-connector-is-registered-adde.patch @@ -0,0 +1,42 @@ +From 1f5f98bf75d3035c62333f498b78edca3abd38a2 Mon Sep 17 00:00:00 2001 +From: Imre Deak +Date: Thu, 12 Dec 2024 01:03:25 +0200 +Subject: [PATCH 019/126] drm/connector: Warn if a connector is + registered/added incorrectly + +All the drivers should be converted now to use +drm_connector_dynamic_init() for MST connectors, hence +drm_connector_dynamic_register()->drm_connector_add() can WARN now if +this was not the case (for instance if a driver inited an MST connector +with one of the drm_connector_init*() functions incorrectly). + +Reviewed-by: Lyude Paul +Reviewed-by: Jani Nikula +Acked-by: Alex Deucher +Acked-by: Wayne Lin +Signed-off-by: Imre Deak +Link: https://patchwork.freedesktop.org/patch/msgid/20241211230328.4012496-9-imre.deak@intel.com +--- + drivers/gpu/drm/drm_connector.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index 3c6c0d7b9..ae6e71305 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -331,11 +331,7 @@ static void drm_connector_add(struct drm_connector *connector) + struct drm_device *dev = connector->dev; + struct drm_mode_config *config = &dev->mode_config; + +- /* +- * TODO: Change this to a WARN, once all drivers are converted to +- * call drm_connector_dynamic_init() for MST connectors. +- */ +- if (!list_empty(&connector->head)) ++ if (drm_WARN_ON(dev, !list_empty(&connector->head))) + return; + + spin_lock_irq(&config->connector_list_lock); +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0020-drm-display-bridge_connector-use-drm_bridge_connecto.patch b/patch/kernel/archive/meson-6.13/0020-drm-display-bridge_connector-use-drm_bridge_connecto.patch new file mode 100644 index 000000000000..27644de977c5 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0020-drm-display-bridge_connector-use-drm_bridge_connecto.patch @@ -0,0 +1,57 @@ +From 7fce81319346688274017f3bb25f2785f115f03e Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Sat, 30 Nov 2024 03:52:32 +0200 +Subject: [PATCH 020/126] drm/display: bridge_connector: use + drm_bridge_connector_mode_valid() + +Use new drm_bridge_connector_mode_valid() helper if there is a HDMI +bridge in the bridge chain. This removes the need to perform TMDS char +rate check manually in the bridge driver. + +Reviewed-by: Chen-Yu Tsai +Reviewed-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241130-hdmi-mode-valid-v5-7-742644ec3b1f@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/display/drm_bridge_connector.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c +index 320c29700..512ced87e 100644 +--- a/drivers/gpu/drm/display/drm_bridge_connector.c ++++ b/drivers/gpu/drm/display/drm_bridge_connector.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + + /** +@@ -299,9 +300,22 @@ static int drm_bridge_connector_get_modes(struct drm_connector *connector) + return 0; + } + ++static enum drm_mode_status ++drm_bridge_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ ++ if (bridge_connector->bridge_hdmi) ++ return drm_hdmi_connector_mode_valid(connector, mode); ++ ++ return MODE_OK; ++} ++ + static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = { + .get_modes = drm_bridge_connector_get_modes, +- /* No need for .mode_valid(), the bridges are checked by the core. */ ++ .mode_valid = drm_bridge_connector_mode_valid, + .enable_hpd = drm_bridge_connector_enable_hpd, + .disable_hpd = drm_bridge_connector_disable_hpd, + }; +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0021-drm-display-bridge_connector-provide-atomic_check-fo.patch b/patch/kernel/archive/meson-6.13/0021-drm-display-bridge_connector-provide-atomic_check-fo.patch new file mode 100644 index 000000000000..b98c413e918a --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0021-drm-display-bridge_connector-provide-atomic_check-fo.patch @@ -0,0 +1,51 @@ +From ea1b70db13b2b8d729f0e04fa7b8c2ed60a9ee64 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 10 Dec 2024 16:16:47 +0200 +Subject: [PATCH 021/126] drm/display: bridge_connector: provide atomic_check + for HDMI bridges + +The bridges using HDMI connector framework have a call to +drm_atomic_helper_connector_hdmi_check() in their atomic_check() +callback. In order to reduce boilerplate and make simplify bridge's +code, use drm_atomic_helper_connector_hdmi_check() to implement +drm_connector.atomic_check() for HDMI bridges. + +Acked-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241210-bridge_hdmi_check-v1-1-a8fdd8c5afa5@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/display/drm_bridge_connector.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c +index 512ced87e..f6e0b6f1f 100644 +--- a/drivers/gpu/drm/display/drm_bridge_connector.c ++++ b/drivers/gpu/drm/display/drm_bridge_connector.c +@@ -313,11 +313,24 @@ drm_bridge_connector_mode_valid(struct drm_connector *connector, + return MODE_OK; + } + ++static int drm_bridge_connector_atomic_check(struct drm_connector *connector, ++ struct drm_atomic_state *state) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ ++ if (bridge_connector->bridge_hdmi) ++ return drm_atomic_helper_connector_hdmi_check(connector, state); ++ ++ return 0; ++} ++ + static const struct drm_connector_helper_funcs drm_bridge_connector_helper_funcs = { + .get_modes = drm_bridge_connector_get_modes, + .mode_valid = drm_bridge_connector_mode_valid, + .enable_hpd = drm_bridge_connector_enable_hpd, + .disable_hpd = drm_bridge_connector_disable_hpd, ++ .atomic_check = drm_bridge_connector_atomic_check, + }; + + static enum drm_mode_status +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0022-drm-tests-hdmi-handle-empty-modes-in-find_preferred_.patch b/patch/kernel/archive/meson-6.13/0022-drm-tests-hdmi-handle-empty-modes-in-find_preferred_.patch new file mode 100644 index 000000000000..4bdecbff27c1 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0022-drm-tests-hdmi-handle-empty-modes-in-find_preferred_.patch @@ -0,0 +1,32 @@ +From 6c46a8c50f9a85379c727ba4b764f70c23e261bf Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Sat, 30 Nov 2024 03:52:26 +0200 +Subject: [PATCH 022/126] drm/tests: hdmi: handle empty modes in + find_preferred_mode() + +If the connector->modes list is empty, then list_first_entry() returns a +bogus entry. Change that to use list_first_entry_or_null(). + +Reviewed-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241130-hdmi-mode-valid-v5-1-742644ec3b1f@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +index 294773342..1e77689af 100644 +--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c ++++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +@@ -46,7 +46,7 @@ static struct drm_display_mode *find_preferred_mode(struct drm_connector *connec + struct drm_display_mode *mode, *preferred; + + mutex_lock(&drm->mode_config.mutex); +- preferred = list_first_entry(&connector->modes, struct drm_display_mode, head); ++ preferred = list_first_entry_or_null(&connector->modes, struct drm_display_mode, head); + list_for_each_entry(mode, &connector->modes, head) + if (mode->type & DRM_MODE_TYPE_PREFERRED) + preferred = mode; +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0023-drm-tests-hdmi-rename-connector-creation-function.patch b/patch/kernel/archive/meson-6.13/0023-drm-tests-hdmi-rename-connector-creation-function.patch new file mode 100644 index 000000000000..80e6a0fa3b1a --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0023-drm-tests-hdmi-rename-connector-creation-function.patch @@ -0,0 +1,429 @@ +From a91a58099618536b80ba7d3673f733883c84baa7 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Sat, 30 Nov 2024 03:52:27 +0200 +Subject: [PATCH 023/126] drm/tests: hdmi: rename connector creation function + +As pointed out by Maxime, the drm_atomic_helper_connector_hdmi_init() +isn't a good name for a function inside KUnit tests. Rename it to +drm_kunit_helper_connector_hdmi_init(). + +Suggested-by: Maxime Ripard +Reviewed-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241130-hdmi-mode-valid-v5-2-742644ec3b1f@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + .../drm/tests/drm_hdmi_state_helper_test.c | 202 +++++++++--------- + 1 file changed, 101 insertions(+), 101 deletions(-) + +diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +index 1e77689af..60b1e3752 100644 +--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c ++++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +@@ -164,9 +164,9 @@ static const struct drm_connector_funcs dummy_connector_funcs = { + + static + struct drm_atomic_helper_connector_hdmi_priv * +-drm_atomic_helper_connector_hdmi_init(struct kunit *test, +- unsigned int formats, +- unsigned int max_bpc) ++drm_kunit_helper_connector_hdmi_init(struct kunit *test, ++ unsigned int formats, ++ unsigned int max_bpc) + { + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector *conn; +@@ -247,9 +247,9 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); +@@ -310,9 +310,9 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); +@@ -373,9 +373,9 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -429,9 +429,9 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; +@@ -485,9 +485,9 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -543,9 +543,9 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; +@@ -601,9 +601,9 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -659,9 +659,9 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; +@@ -719,9 +719,9 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 10); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -793,9 +793,9 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 10); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -862,11 +862,11 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -911,9 +911,9 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -958,9 +958,9 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 10); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1005,9 +1005,9 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1056,9 +1056,9 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); +@@ -1112,9 +1112,9 @@ static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1179,11 +1179,11 @@ static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1242,11 +1242,11 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + drm = &priv->drm; +@@ -1305,9 +1305,9 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test) + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1370,11 +1370,11 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1438,9 +1438,9 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1496,11 +1496,11 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes + struct drm_crtc *crtc; + int ret; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1593,9 +1593,9 @@ static void drm_test_check_broadcast_rgb_value(struct kunit *test) + struct drm_connector_state *conn_state; + struct drm_connector *conn; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1615,9 +1615,9 @@ static void drm_test_check_bpc_8_value(struct kunit *test) + struct drm_connector_state *conn_state; + struct drm_connector *conn; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1639,9 +1639,9 @@ static void drm_test_check_bpc_10_value(struct kunit *test) + struct drm_connector_state *conn_state; + struct drm_connector *conn; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 10); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 10); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1663,9 +1663,9 @@ static void drm_test_check_bpc_12_value(struct kunit *test) + struct drm_connector_state *conn_state; + struct drm_connector *conn; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1685,11 +1685,11 @@ static void drm_test_check_format_value(struct kunit *test) + struct drm_connector_state *conn_state; + struct drm_connector *conn; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 8); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 8); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +@@ -1707,11 +1707,11 @@ static void drm_test_check_tmds_char_value(struct kunit *test) + struct drm_connector_state *conn_state; + struct drm_connector *conn; + +- priv = drm_atomic_helper_connector_hdmi_init(test, +- BIT(HDMI_COLORSPACE_RGB) | +- BIT(HDMI_COLORSPACE_YUV422) | +- BIT(HDMI_COLORSPACE_YUV444), +- 12); ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444), ++ 12); + KUNIT_ASSERT_NOT_NULL(test, priv); + + conn = &priv->connector; +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0024-drm-tests-hdmi-return-meaningful-value-from-set_conn.patch b/patch/kernel/archive/meson-6.13/0024-drm-tests-hdmi-return-meaningful-value-from-set_conn.patch new file mode 100644 index 000000000000..85dc671617dd --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0024-drm-tests-hdmi-return-meaningful-value-from-set_conn.patch @@ -0,0 +1,162 @@ +From 989feed72531b7d6c489ad81cc08b7316e0628a5 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Sat, 30 Nov 2024 03:52:28 +0200 +Subject: [PATCH 024/126] drm/tests: hdmi: return meaningful value from + set_connector_edid() + +The set_connector_edid() function returns a bogus 0, performing the +check on the connector->funcs->fill_modes() result internally. Make the +function pass the fill_modes()'s return value to the caller and move +corresponding checks to the caller site. + +Reviewed-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241130-hdmi-mode-valid-v5-3-742644ec3b1f@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + .../drm/tests/drm_hdmi_state_helper_test.c | 31 +++++++++---------- + 1 file changed, 15 insertions(+), 16 deletions(-) + +diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +index 60b1e3752..19384b5ff 100644 +--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c ++++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +@@ -105,9 +105,8 @@ static int set_connector_edid(struct kunit *test, struct drm_connector *connecto + mutex_lock(&drm->mode_config.mutex); + ret = connector->funcs->fill_modes(connector, 4096, 4096); + mutex_unlock(&drm->mode_config.mutex); +- KUNIT_ASSERT_GT(test, ret, 0); + +- return 0; ++ return ret; + } + + static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = { +@@ -223,7 +222,7 @@ drm_kunit_helper_connector_hdmi_init(struct kunit *test, + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + return priv; + } +@@ -728,7 +727,7 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); +@@ -802,7 +801,7 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); +@@ -873,7 +872,7 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_dvi_1080p, + ARRAY_SIZE(test_edid_dvi_1080p)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_FALSE(test, info->is_hdmi); +@@ -920,7 +919,7 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); +@@ -967,7 +966,7 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); +@@ -1014,7 +1013,7 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + ctx = drm_kunit_helper_acquire_ctx_alloc(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); +@@ -1121,7 +1120,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +@@ -1190,7 +1189,7 @@ static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +@@ -1254,7 +1253,7 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +@@ -1314,7 +1313,7 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test) + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +@@ -1381,7 +1380,7 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +@@ -1447,7 +1446,7 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +@@ -1507,7 +1506,7 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes + ret = set_connector_edid(test, conn, + test_edid_hdmi_1080p_rgb_max_340mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_340mhz)); +- KUNIT_ASSERT_EQ(test, ret, 0); ++ KUNIT_ASSERT_GT(test, ret, 0); + + info = &conn->display_info; + KUNIT_ASSERT_TRUE(test, info->is_hdmi); +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0025-drm-display-hdmi-add-generic-mode_valid-helper.patch b/patch/kernel/archive/meson-6.13/0025-drm-display-hdmi-add-generic-mode_valid-helper.patch new file mode 100644 index 000000000000..7f6d9fbd6547 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0025-drm-display-hdmi-add-generic-mode_valid-helper.patch @@ -0,0 +1,408 @@ +From 42ca7c83f9f56fe7be79845a369864d941dfb7a1 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Sat, 30 Nov 2024 03:52:29 +0200 +Subject: [PATCH 025/126] drm/display: hdmi: add generic mode_valid helper + +Add drm_hdmi_connector_mode_valid(), generic helper for HDMI connectors. +It can be either used directly or as a part of the .mode_valid callback. + +Reviewed-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241130-hdmi-mode-valid-v5-4-742644ec3b1f@linaro.org +Signed-off-by: Dmitry Baryshkov +--- + .../gpu/drm/display/drm_hdmi_state_helper.c | 21 ++ + .../drm/tests/drm_hdmi_state_helper_test.c | 180 +++++++++++++++++- + drivers/gpu/drm/tests/drm_kunit_edid.h | 102 ++++++++++ + include/drm/display/drm_hdmi_state_helper.h | 4 + + 4 files changed, 302 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c +index feb7a3a75..80bf2829b 100644 +--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c ++++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c +@@ -521,6 +521,27 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector, + } + EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check); + ++/** ++ * drm_hdmi_connector_mode_valid() - Check if mode is valid for HDMI connector ++ * @connector: DRM connector to validate the mode ++ * @mode: Display mode to validate ++ * ++ * Generic .mode_valid implementation for HDMI connectors. ++ */ ++enum drm_mode_status ++drm_hdmi_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode) ++{ ++ unsigned long long clock; ++ ++ clock = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); ++ if (!clock) ++ return MODE_ERROR; ++ ++ return hdmi_clock_valid(connector, mode, clock); ++} ++EXPORT_SYMBOL(drm_hdmi_connector_mode_valid); ++ + static int clear_device_infoframe(struct drm_connector *connector, + enum hdmi_infoframe_type type) + { +diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +index 19384b5ff..c3b693bb9 100644 +--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c ++++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c +@@ -124,6 +124,18 @@ static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = { + .tmds_char_rate_valid = reject_connector_tmds_char_rate_valid, + }; + ++static enum drm_mode_status ++reject_100MHz_connector_tmds_char_rate_valid(const struct drm_connector *connector, ++ const struct drm_display_mode *mode, ++ unsigned long long tmds_rate) ++{ ++ return (tmds_rate > 100ULL * 1000 * 1000) ? MODE_BAD : MODE_OK; ++} ++ ++static const struct drm_connector_hdmi_funcs reject_100_MHz_connector_hdmi_funcs = { ++ .tmds_char_rate_valid = reject_100MHz_connector_tmds_char_rate_valid, ++}; ++ + static int dummy_connector_get_modes(struct drm_connector *connector) + { + struct drm_atomic_helper_connector_hdmi_priv *priv = +@@ -146,6 +158,7 @@ static int dummy_connector_get_modes(struct drm_connector *connector) + static const struct drm_connector_helper_funcs dummy_connector_helper_funcs = { + .atomic_check = drm_atomic_helper_connector_hdmi_check, + .get_modes = dummy_connector_get_modes, ++ .mode_valid = drm_hdmi_connector_mode_valid, + }; + + static void dummy_hdmi_connector_reset(struct drm_connector *connector) +@@ -163,9 +176,10 @@ static const struct drm_connector_funcs dummy_connector_funcs = { + + static + struct drm_atomic_helper_connector_hdmi_priv * +-drm_kunit_helper_connector_hdmi_init(struct kunit *test, +- unsigned int formats, +- unsigned int max_bpc) ++drm_kunit_helper_connector_hdmi_init_funcs(struct kunit *test, ++ unsigned int formats, ++ unsigned int max_bpc, ++ const struct drm_connector_hdmi_funcs *hdmi_funcs) + { + struct drm_atomic_helper_connector_hdmi_priv *priv; + struct drm_connector *conn; +@@ -207,7 +221,7 @@ drm_kunit_helper_connector_hdmi_init(struct kunit *test, + ret = drmm_connector_hdmi_init(drm, conn, + "Vendor", "Product", + &dummy_connector_funcs, +- &dummy_connector_hdmi_funcs, ++ hdmi_funcs, + DRM_MODE_CONNECTOR_HDMIA, + NULL, + formats, +@@ -219,7 +233,24 @@ drm_kunit_helper_connector_hdmi_init(struct kunit *test, + + drm_mode_config_reset(drm); + +- ret = set_connector_edid(test, conn, ++ return priv; ++} ++ ++static ++struct drm_atomic_helper_connector_hdmi_priv * ++drm_kunit_helper_connector_hdmi_init(struct kunit *test, ++ unsigned int formats, ++ unsigned int max_bpc) ++{ ++ struct drm_atomic_helper_connector_hdmi_priv *priv; ++ int ret; ++ ++ priv = drm_kunit_helper_connector_hdmi_init_funcs(test, ++ formats, max_bpc, ++ &dummy_connector_hdmi_funcs); ++ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); ++ ++ ret = set_connector_edid(test, &priv->connector, + test_edid_hdmi_1080p_rgb_max_200mhz, + ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); + KUNIT_ASSERT_GT(test, ret, 0); +@@ -1733,9 +1764,148 @@ static struct kunit_suite drm_atomic_helper_connector_hdmi_reset_test_suite = { + .test_cases = drm_atomic_helper_connector_hdmi_reset_tests, + }; + ++/* ++ * Test that the default behaviour for drm_hdmi_connector_mode_valid() is not ++ * to reject any modes. Pass a correct EDID and verify that preferred mode ++ * matches the expectations (1080p). ++ */ ++static void drm_test_check_mode_valid(struct kunit *test) ++{ ++ struct drm_atomic_helper_connector_hdmi_priv *priv; ++ struct drm_connector *conn; ++ struct drm_display_mode *preferred; ++ ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); ++ KUNIT_ASSERT_NOT_NULL(test, priv); ++ ++ conn = &priv->connector; ++ preferred = find_preferred_mode(conn); ++ KUNIT_ASSERT_NOT_NULL(test, preferred); ++ ++ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 1920); ++ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 1080); ++ KUNIT_EXPECT_EQ(test, preferred->clock, 148500); ++} ++ ++/* ++ * Test that the drm_hdmi_connector_mode_valid() will reject modes depending on ++ * the .tmds_char_rate_valid() behaviour. ++ * Pass a correct EDID and verify that high-rate modes are filtered. ++ */ ++static void drm_test_check_mode_valid_reject_rate(struct kunit *test) ++{ ++ struct drm_atomic_helper_connector_hdmi_priv *priv; ++ struct drm_connector *conn; ++ struct drm_display_mode *preferred; ++ int ret; ++ ++ priv = drm_kunit_helper_connector_hdmi_init_funcs(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8, ++ &reject_100_MHz_connector_hdmi_funcs); ++ KUNIT_ASSERT_NOT_NULL(test, priv); ++ ++ conn = &priv->connector; ++ ++ ret = set_connector_edid(test, conn, ++ test_edid_hdmi_1080p_rgb_max_200mhz, ++ ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); ++ KUNIT_ASSERT_GT(test, ret, 0); ++ ++ /* ++ * Unlike the drm_test_check_mode_valid() here 1080p is rejected, but ++ * 480p is allowed. ++ */ ++ preferred = find_preferred_mode(conn); ++ KUNIT_ASSERT_NOT_NULL(test, preferred); ++ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640); ++ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480); ++ KUNIT_EXPECT_EQ(test, preferred->clock, 25200); ++} ++ ++/* ++ * Test that the drm_hdmi_connector_mode_valid() will not mark any modes as ++ * valid if .tmds_char_rate_valid() rejects all of them. Pass a correct EDID ++ * and verify that there is no preferred mode and no modes were set for the ++ * connector. ++ */ ++static void drm_test_check_mode_valid_reject(struct kunit *test) ++{ ++ struct drm_atomic_helper_connector_hdmi_priv *priv; ++ struct drm_connector *conn; ++ struct drm_display_mode *preferred; ++ int ret; ++ ++ priv = drm_kunit_helper_connector_hdmi_init_funcs(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8, ++ &reject_connector_hdmi_funcs); ++ KUNIT_ASSERT_NOT_NULL(test, priv); ++ ++ conn = &priv->connector; ++ ++ /* should reject all modes */ ++ ret = set_connector_edid(test, conn, ++ test_edid_hdmi_1080p_rgb_max_200mhz, ++ ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_200mhz)); ++ KUNIT_ASSERT_EQ(test, ret, 0); ++ ++ preferred = find_preferred_mode(conn); ++ KUNIT_ASSERT_NULL(test, preferred); ++} ++ ++/* ++ * Test that the drm_hdmi_connector_mode_valid() will reject modes that don't ++ * pass the info.max_tmds_clock filter. Pass crafted EDID and verify that ++ * high-rate modes are filtered. ++ */ ++static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test) ++{ ++ struct drm_atomic_helper_connector_hdmi_priv *priv; ++ struct drm_connector *conn; ++ struct drm_display_mode *preferred; ++ int ret; ++ ++ priv = drm_kunit_helper_connector_hdmi_init(test, ++ BIT(HDMI_COLORSPACE_RGB), ++ 8); ++ KUNIT_ASSERT_NOT_NULL(test, priv); ++ ++ conn = &priv->connector; ++ ++ ret = set_connector_edid(test, conn, ++ test_edid_hdmi_1080p_rgb_max_100mhz, ++ ARRAY_SIZE(test_edid_hdmi_1080p_rgb_max_100mhz)); ++ KUNIT_ASSERT_GT(test, ret, 0); ++ ++ KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 100 * 1000); ++ ++ preferred = find_preferred_mode(conn); ++ KUNIT_ASSERT_NOT_NULL(test, preferred); ++ KUNIT_EXPECT_EQ(test, preferred->hdisplay, 640); ++ KUNIT_EXPECT_EQ(test, preferred->vdisplay, 480); ++ KUNIT_EXPECT_EQ(test, preferred->clock, 25200); ++} ++ ++static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = { ++ KUNIT_CASE(drm_test_check_mode_valid), ++ KUNIT_CASE(drm_test_check_mode_valid_reject), ++ KUNIT_CASE(drm_test_check_mode_valid_reject_rate), ++ KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock), ++ { } ++}; ++ ++static struct kunit_suite drm_atomic_helper_connector_hdmi_mode_valid_test_suite = { ++ .name = "drm_atomic_helper_connector_hdmi_mode_valid", ++ .test_cases = drm_atomic_helper_connector_hdmi_mode_valid_tests, ++}; ++ + kunit_test_suites( + &drm_atomic_helper_connector_hdmi_check_test_suite, + &drm_atomic_helper_connector_hdmi_reset_test_suite, ++ &drm_atomic_helper_connector_hdmi_mode_valid_test_suite, + ); + + MODULE_AUTHOR("Maxime Ripard "); +diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h +index 107559900..6358397a5 100644 +--- a/drivers/gpu/drm/tests/drm_kunit_edid.h ++++ b/drivers/gpu/drm/tests/drm_kunit_edid.h +@@ -61,6 +61,108 @@ static const unsigned char test_edid_dvi_1080p[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab + }; + ++/* ++ * edid-decode (hex): ++ * ++ * 00 ff ff ff ff ff ff 00 31 d8 2a 00 00 00 00 00 ++ * 00 21 01 03 81 a0 5a 78 02 00 00 00 00 00 00 00 ++ * 00 00 00 20 00 00 01 01 01 01 01 01 01 01 01 01 ++ * 01 01 01 01 01 01 02 3a 80 18 71 38 2d 40 58 2c ++ * 45 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73 ++ * 74 20 45 44 49 44 0a 20 20 20 00 00 00 fd 00 32 ++ * 46 1e 46 0f 00 0a 20 20 20 20 20 20 00 00 00 10 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 92 ++ * ++ * 02 03 1b 81 e3 05 00 20 41 10 e2 00 4a 6d 03 0c ++ * 00 12 34 00 14 20 00 00 00 00 00 00 00 00 00 00 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ++ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e4 ++ * ++ * ---------------- ++ * ++ * Block 0, Base EDID: ++ * EDID Structure Version & Revision: 1.3 ++ * Vendor & Product Identification: ++ * Manufacturer: LNX ++ * Model: 42 ++ * Made in: 2023 ++ * Basic Display Parameters & Features: ++ * Digital display ++ * DFP 1.x compatible TMDS ++ * Maximum image size: 160 cm x 90 cm ++ * Gamma: 2.20 ++ * Monochrome or grayscale display ++ * First detailed timing is the preferred timing ++ * Color Characteristics: ++ * Red : 0.0000, 0.0000 ++ * Green: 0.0000, 0.0000 ++ * Blue : 0.0000, 0.0000 ++ * White: 0.0000, 0.0000 ++ * Established Timings I & II: ++ * DMT 0x04: 640x480 59.940476 Hz 4:3 31.469 kHz 25.175000 MHz ++ * Standard Timings: none ++ * Detailed Timing Descriptors: ++ * DTD 1: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz (1600 mm x 900 mm) ++ * Hfront 88 Hsync 44 Hback 148 Hpol P ++ * Vfront 4 Vsync 5 Vback 36 Vpol P ++ * Display Product Name: 'Test EDID' ++ * Display Range Limits: ++ * Monitor ranges (GTF): 50-70 Hz V, 30-70 kHz H, max dotclock 150 MHz ++ * Dummy Descriptor: ++ * Extension blocks: 1 ++ * Checksum: 0x92 ++ * ++ * ---------------- ++ * ++ * Block 1, CTA-861 Extension Block: ++ * Revision: 3 ++ * Underscans IT Video Formats by default ++ * Native detailed modes: 1 ++ * Colorimetry Data Block: ++ * sRGB ++ * Video Data Block: ++ * VIC 16: 1920x1080 60.000000 Hz 16:9 67.500 kHz 148.500000 MHz ++ * Video Capability Data Block: ++ * YCbCr quantization: No Data ++ * RGB quantization: Selectable (via AVI Q) ++ * PT scan behavior: No Data ++ * IT scan behavior: Always Underscanned ++ * CE scan behavior: Always Underscanned ++ * Vendor-Specific Data Block (HDMI), OUI 00-0C-03: ++ * Source physical address: 1.2.3.4 ++ * Maximum TMDS clock: 100 MHz ++ * Extended HDMI video details: ++ * Checksum: 0xe4 Unused space in Extension Block: 100 bytes ++ */ ++static const unsigned char test_edid_hdmi_1080p_rgb_max_100mhz[] = { ++ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x2a, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x03, 0x81, 0xa0, 0x5a, 0x78, ++ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, ++ 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, ++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, ++ 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e, ++ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x44, ++ 0x49, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, ++ 0x46, 0x00, 0x00, 0xc4, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x02, 0x03, 0x1b, 0x81, ++ 0xe3, 0x05, 0x00, 0x20, 0x41, 0x10, 0xe2, 0x00, 0x4a, 0x6d, 0x03, 0x0c, ++ 0x00, 0x12, 0x34, 0x00, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0xe4 ++}; ++ + /* + * edid-decode (hex): + * +diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h +index 2d45fcfa4..d6d65da6d 100644 +--- a/include/drm/display/drm_hdmi_state_helper.h ++++ b/include/drm/display/drm_hdmi_state_helper.h +@@ -20,4 +20,8 @@ int drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector + int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector, + struct drm_atomic_state *state); + ++enum drm_mode_status ++drm_hdmi_connector_mode_valid(struct drm_connector *connector, ++ struct drm_display_mode *mode); ++ + #endif // DRM_HDMI_STATE_HELPER_H_ +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0026-ASoC-hdmi-codec-pass-data-to-get_dai_id-too.patch b/patch/kernel/archive/meson-6.13/0026-ASoC-hdmi-codec-pass-data-to-get_dai_id-too.patch new file mode 100644 index 000000000000..de8d72c4f08b --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0026-ASoC-hdmi-codec-pass-data-to-get_dai_id-too.patch @@ -0,0 +1,137 @@ +From 6fe6c8b5d8a46f66974034d005e92224d5f7093c Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 24 Dec 2024 03:47:53 +0200 +Subject: [PATCH 026/126] ASoC: hdmi-codec: pass data to get_dai_id too + +The upcoming DRM connector HDMI codec implementation is going to use +codec-specific data in the .get_dai_id to get drm_connector. Pass data +to the callback, as it is done with other hdmi_codec_ops callbacks. + +Acked-by: Mark Brown +Tested-by: Dave Stevenson +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/bridge/adv7511/adv7511_audio.c | 3 ++- + drivers/gpu/drm/bridge/analogix/anx7625.c | 3 ++- + drivers/gpu/drm/bridge/lontium-lt9611.c | 3 ++- + drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 3 ++- + drivers/gpu/drm/bridge/sii902x.c | 3 ++- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 3 ++- + include/sound/hdmi-codec.h | 3 ++- + sound/soc/codecs/hdmi-codec.c | 2 +- + 8 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +index 8f7865921..657bc3dd1 100644 +--- a/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c ++++ b/drivers/gpu/drm/bridge/adv7511/adv7511_audio.c +@@ -214,7 +214,8 @@ static void audio_shutdown(struct device *dev, void *data) + } + + static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component, +- struct device_node *endpoint) ++ struct device_node *endpoint, ++ void *data) + { + struct of_endpoint of_ep; + int ret; +diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c +index a2675b121..926437346 100644 +--- a/drivers/gpu/drm/bridge/analogix/anx7625.c ++++ b/drivers/gpu/drm/bridge/analogix/anx7625.c +@@ -1952,7 +1952,8 @@ static void anx7625_audio_shutdown(struct device *dev, void *data) + } + + static int anx7625_hdmi_i2s_get_dai_id(struct snd_soc_component *component, +- struct device_node *endpoint) ++ struct device_node *endpoint, ++ void *data) + { + struct of_endpoint of_ep; + int ret; +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c +index 1b31fdebe..4fa0dfc55 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611.c +@@ -1059,7 +1059,8 @@ static void lt9611_audio_shutdown(struct device *dev, void *data) + } + + static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component, +- struct device_node *endpoint) ++ struct device_node *endpoint, ++ void *data) + { + struct of_endpoint of_ep; + int ret; +diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +index 4d1d40e1f..fd26aa36b 100644 +--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c ++++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +@@ -522,7 +522,8 @@ static void lt9611uxc_audio_shutdown(struct device *dev, void *data) + } + + static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component, +- struct device_node *endpoint) ++ struct device_node *endpoint, ++ void *data) + { + struct of_endpoint of_ep; + int ret; +diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c +index 9be9cc5b9..f0be803cc 100644 +--- a/drivers/gpu/drm/bridge/sii902x.c ++++ b/drivers/gpu/drm/bridge/sii902x.c +@@ -815,7 +815,8 @@ static int sii902x_audio_get_eld(struct device *dev, void *data, + } + + static int sii902x_audio_get_dai_id(struct snd_soc_component *component, +- struct device_node *endpoint) ++ struct device_node *endpoint, ++ void *data) + { + struct of_endpoint of_ep; + int ret; +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index f1c5a8d0f..2c903c9fe 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -148,7 +148,8 @@ static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, uint8_t *buf, + } + + static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, +- struct device_node *endpoint) ++ struct device_node *endpoint, ++ void *data) + { + struct of_endpoint of_ep; + int ret; +diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h +index 5e1a9eafd..b3407b47b 100644 +--- a/include/sound/hdmi-codec.h ++++ b/include/sound/hdmi-codec.h +@@ -105,7 +105,8 @@ struct hdmi_codec_ops { + * Optional + */ + int (*get_dai_id)(struct snd_soc_component *comment, +- struct device_node *endpoint); ++ struct device_node *endpoint, ++ void *data); + + /* + * Hook callback function to handle connector plug event. +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index d9df29a26..f536ca60e 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -995,7 +995,7 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, + int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */ + + if (hcp->hcd.ops->get_dai_id) +- ret = hcp->hcd.ops->get_dai_id(component, endpoint); ++ ret = hcp->hcd.ops->get_dai_id(component, endpoint, hcp->hcd.data); + + return ret; + } +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0027-ASoC-hdmi-codec-move-no_capture_mute-to-struct-hdmi_.patch b/patch/kernel/archive/meson-6.13/0027-ASoC-hdmi-codec-move-no_capture_mute-to-struct-hdmi_.patch new file mode 100644 index 000000000000..d91a8464cb7b --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0027-ASoC-hdmi-codec-move-no_capture_mute-to-struct-hdmi_.patch @@ -0,0 +1,225 @@ +From d058ddc63634026b5e73513b6bbc0b1ca4a91825 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 24 Dec 2024 03:47:54 +0200 +Subject: [PATCH 027/126] ASoC: hdmi-codec: move no_capture_mute to struct + hdmi_codec_pdata + +The no_capture_mute flag might differ from platform to platform, +especially in the case of the wrapping implementations, like the +upcoming DRM HDMI Codec framework. Move the flag next to all other flags +in struct hdmi_codec_pdata. + +Acked-by: Mark Brown +Tested-by: Dave Stevenson +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/bridge/ite-it66121.c | 2 +- + drivers/gpu/drm/bridge/sii902x.c | 2 +- + drivers/gpu/drm/exynos/exynos_hdmi.c | 2 +- + drivers/gpu/drm/i2c/tda998x_drv.c | 2 +- + drivers/gpu/drm/mediatek/mtk_dp.c | 2 +- + drivers/gpu/drm/mediatek/mtk_hdmi.c | 2 +- + drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +- + drivers/gpu/drm/sti/sti_hdmi.c | 2 +- + include/sound/hdmi-codec.h | 4 +--- + sound/soc/codecs/hdmi-codec.c | 2 +- + 10 files changed, 10 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c +index 35ae3f0e8..98669470d 100644 +--- a/drivers/gpu/drm/bridge/ite-it66121.c ++++ b/drivers/gpu/drm/bridge/ite-it66121.c +@@ -1464,7 +1464,6 @@ static const struct hdmi_codec_ops it66121_audio_codec_ops = { + .audio_shutdown = it66121_audio_shutdown, + .mute_stream = it66121_audio_mute, + .get_eld = it66121_audio_get_eld, +- .no_capture_mute = 1, + }; + + static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev) +@@ -1474,6 +1473,7 @@ static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev) + .i2s = 1, /* Only i2s support for now */ + .spdif = 0, + .max_i2s_channels = 8, ++ .no_capture_mute = 1, + }; + + dev_dbg(dev, "%s\n", __func__); +diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c +index f0be803cc..5248676b0 100644 +--- a/drivers/gpu/drm/bridge/sii902x.c ++++ b/drivers/gpu/drm/bridge/sii902x.c +@@ -841,7 +841,6 @@ static const struct hdmi_codec_ops sii902x_audio_codec_ops = { + .mute_stream = sii902x_audio_mute, + .get_eld = sii902x_audio_get_eld, + .get_dai_id = sii902x_audio_get_dai_id, +- .no_capture_mute = 1, + }; + + static int sii902x_audio_codec_init(struct sii902x *sii902x, +@@ -864,6 +863,7 @@ static int sii902x_audio_codec_init(struct sii902x *sii902x, + .i2s = 1, /* Only i2s support for now. */ + .spdif = 0, + .max_i2s_channels = 0, ++ .no_capture_mute = 1, + }; + u8 lanes[4]; + int num_lanes, i; +diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c +index 466a9e514..689168fd6 100644 +--- a/drivers/gpu/drm/exynos/exynos_hdmi.c ++++ b/drivers/gpu/drm/exynos/exynos_hdmi.c +@@ -1658,7 +1658,6 @@ static const struct hdmi_codec_ops audio_codec_ops = { + .audio_shutdown = hdmi_audio_shutdown, + .mute_stream = hdmi_audio_mute, + .get_eld = hdmi_audio_get_eld, +- .no_capture_mute = 1, + }; + + static int hdmi_register_audio_device(struct hdmi_context *hdata) +@@ -1667,6 +1666,7 @@ static int hdmi_register_audio_device(struct hdmi_context *hdata) + .ops = &audio_codec_ops, + .max_i2s_channels = 6, + .i2s = 1, ++ .no_capture_mute = 1, + }; + + hdata->audio.pdev = platform_device_register_data( +diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c +index 2160f05bb..10a4195d6 100644 +--- a/drivers/gpu/drm/i2c/tda998x_drv.c ++++ b/drivers/gpu/drm/i2c/tda998x_drv.c +@@ -1165,7 +1165,6 @@ static const struct hdmi_codec_ops audio_codec_ops = { + .audio_shutdown = tda998x_audio_shutdown, + .mute_stream = tda998x_audio_mute_stream, + .get_eld = tda998x_audio_get_eld, +- .no_capture_mute = 1, + }; + + static int tda998x_audio_codec_init(struct tda998x_priv *priv, +@@ -1176,6 +1175,7 @@ static int tda998x_audio_codec_init(struct tda998x_priv *priv, + .max_i2s_channels = 2, + .no_i2s_capture = 1, + .no_spdif_capture = 1, ++ .no_capture_mute = 1, + }; + + if (priv->audio_port_enable[AUDIO_ROUTE_I2S]) +diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c +index 3b0993abf..14f40f2e3 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dp.c ++++ b/drivers/gpu/drm/mediatek/mtk_dp.c +@@ -2623,7 +2623,6 @@ static const struct hdmi_codec_ops mtk_dp_audio_codec_ops = { + .audio_shutdown = mtk_dp_audio_shutdown, + .get_eld = mtk_dp_audio_get_eld, + .hook_plugged_cb = mtk_dp_audio_hook_plugged_cb, +- .no_capture_mute = 1, + }; + + static int mtk_dp_register_audio_driver(struct device *dev) +@@ -2634,6 +2633,7 @@ static int mtk_dp_register_audio_driver(struct device *dev) + .max_i2s_channels = 8, + .i2s = 1, + .data = mtk_dp, ++ .no_capture_mute = 1, + }; + + mtk_dp->audio_pdev = platform_device_register_data(dev, +diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c +index 70dc1d446..ca82bc829 100644 +--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c ++++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c +@@ -1660,7 +1660,6 @@ static const struct hdmi_codec_ops mtk_hdmi_audio_codec_ops = { + .mute_stream = mtk_hdmi_audio_mute, + .get_eld = mtk_hdmi_audio_get_eld, + .hook_plugged_cb = mtk_hdmi_audio_hook_plugged_cb, +- .no_capture_mute = 1, + }; + + static int mtk_hdmi_register_audio_driver(struct device *dev) +@@ -1671,6 +1670,7 @@ static int mtk_hdmi_register_audio_driver(struct device *dev) + .max_i2s_channels = 2, + .i2s = 1, + .data = hdmi, ++ .no_capture_mute = 1, + }; + struct platform_device *pdev; + +diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c +index ff9d95e2c..cb1983383 100644 +--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c ++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c +@@ -885,7 +885,6 @@ static const struct hdmi_codec_ops audio_codec_ops = { + .mute_stream = cdn_dp_audio_mute_stream, + .get_eld = cdn_dp_audio_get_eld, + .hook_plugged_cb = cdn_dp_audio_hook_plugged_cb, +- .no_capture_mute = 1, + }; + + static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, +@@ -896,6 +895,7 @@ static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, + .spdif = 1, + .ops = &audio_codec_ops, + .max_i2s_channels = 8, ++ .no_capture_mute = 1, + }; + + dp->audio_pdev = platform_device_register_data( +diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c +index 21b46a646..5f23ad933 100644 +--- a/drivers/gpu/drm/sti/sti_hdmi.c ++++ b/drivers/gpu/drm/sti/sti_hdmi.c +@@ -1235,7 +1235,6 @@ static const struct hdmi_codec_ops audio_codec_ops = { + .audio_shutdown = hdmi_audio_shutdown, + .mute_stream = hdmi_audio_mute, + .get_eld = hdmi_audio_get_eld, +- .no_capture_mute = 1, + }; + + static int sti_hdmi_register_audio_driver(struct device *dev, +@@ -1245,6 +1244,7 @@ static int sti_hdmi_register_audio_driver(struct device *dev, + .ops = &audio_codec_ops, + .max_i2s_channels = 8, + .i2s = 1, ++ .no_capture_mute = 1, + }; + + DRM_DEBUG_DRIVER("\n"); +diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h +index b3407b47b..b220072cf 100644 +--- a/include/sound/hdmi-codec.h ++++ b/include/sound/hdmi-codec.h +@@ -115,9 +115,6 @@ struct hdmi_codec_ops { + int (*hook_plugged_cb)(struct device *dev, void *data, + hdmi_codec_plugged_cb fn, + struct device *codec_dev); +- +- /* bit field */ +- unsigned int no_capture_mute:1; + }; + + /* HDMI codec initalization data */ +@@ -129,6 +126,7 @@ struct hdmi_codec_pdata { + uint spdif:1; + uint no_spdif_playback:1; + uint no_spdif_capture:1; ++ uint no_capture_mute:1; + int max_i2s_channels; + void *data; + }; +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index f536ca60e..69f98975e 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -714,7 +714,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction) + */ + if (hcp->hcd.ops->mute_stream && + (direction == SNDRV_PCM_STREAM_PLAYBACK || +- !hcp->hcd.ops->no_capture_mute)) ++ !hcp->hcd.no_capture_mute)) + return hcp->hcd.ops->mute_stream(dai->dev->parent, + hcp->hcd.data, + mute, direction); +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0028-drm-connector-implement-generic-HDMI-audio-helpers.patch b/patch/kernel/archive/meson-6.13/0028-drm-connector-implement-generic-HDMI-audio-helpers.patch new file mode 100644 index 000000000000..2f542c08206c --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0028-drm-connector-implement-generic-HDMI-audio-helpers.patch @@ -0,0 +1,467 @@ +From ab9d525dc060bca737d9a64bdccf9a7574f8af02 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 24 Dec 2024 03:47:55 +0200 +Subject: [PATCH 028/126] drm/connector: implement generic HDMI audio helpers + +Several DRM drivers implement HDMI codec support (despite its name it +applies to both HDMI and DisplayPort drivers). Implement generic +framework to be used by these drivers. This removes a requirement to +implement get_eld() callback and provides default implementation for +codec's plug handling. + +Acked-by: Maxime Ripard +Tested-by: Dave Stevenson +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/display/Kconfig | 6 + + drivers/gpu/drm/display/Makefile | 2 + + .../gpu/drm/display/drm_hdmi_audio_helper.c | 190 ++++++++++++++++++ + drivers/gpu/drm/drm_connector.c | 5 + + include/drm/display/drm_hdmi_audio_helper.h | 22 ++ + include/drm/drm_connector.h | 116 +++++++++++ + 6 files changed, 341 insertions(+) + create mode 100644 drivers/gpu/drm/display/drm_hdmi_audio_helper.c + create mode 100644 include/drm/display/drm_hdmi_audio_helper.h + +diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig +index 6a4e892af..80c1953ca 100644 +--- a/drivers/gpu/drm/display/Kconfig ++++ b/drivers/gpu/drm/display/Kconfig +@@ -75,6 +75,12 @@ config DRM_DISPLAY_HDCP_HELPER + help + DRM display helpers for HDCP. + ++config DRM_DISPLAY_HDMI_AUDIO_HELPER ++ bool ++ help ++ DRM display helpers for HDMI Audio functionality (generic HDMI Codec ++ implementation). ++ + config DRM_DISPLAY_HDMI_HELPER + bool + help +diff --git a/drivers/gpu/drm/display/Makefile b/drivers/gpu/drm/display/Makefile +index 629c834c3..b17879b95 100644 +--- a/drivers/gpu/drm/display/Makefile ++++ b/drivers/gpu/drm/display/Makefile +@@ -14,6 +14,8 @@ drm_display_helper-$(CONFIG_DRM_DISPLAY_DP_TUNNEL) += \ + drm_display_helper-$(CONFIG_DRM_DISPLAY_DSC_HELPER) += \ + drm_dsc_helper.o + drm_display_helper-$(CONFIG_DRM_DISPLAY_HDCP_HELPER) += drm_hdcp_helper.o ++drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_AUDIO_HELPER) += \ ++ drm_hdmi_audio_helper.o + drm_display_helper-$(CONFIG_DRM_DISPLAY_HDMI_HELPER) += \ + drm_hdmi_helper.o \ + drm_scdc_helper.o +diff --git a/drivers/gpu/drm/display/drm_hdmi_audio_helper.c b/drivers/gpu/drm/display/drm_hdmi_audio_helper.c +new file mode 100644 +index 000000000..05afc9f0b +--- /dev/null ++++ b/drivers/gpu/drm/display/drm_hdmi_audio_helper.c +@@ -0,0 +1,190 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Copyright (c) 2024 Linaro Ltd ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++static int drm_connector_hdmi_audio_startup(struct device *dev, void *data) ++{ ++ struct drm_connector *connector = data; ++ const struct drm_connector_hdmi_audio_funcs *funcs = ++ connector->hdmi_audio.funcs; ++ ++ if (funcs->startup) ++ return funcs->startup(connector); ++ ++ return 0; ++} ++ ++static int drm_connector_hdmi_audio_prepare(struct device *dev, void *data, ++ struct hdmi_codec_daifmt *fmt, ++ struct hdmi_codec_params *hparms) ++{ ++ struct drm_connector *connector = data; ++ const struct drm_connector_hdmi_audio_funcs *funcs = ++ connector->hdmi_audio.funcs; ++ ++ return funcs->prepare(connector, fmt, hparms); ++} ++ ++static void drm_connector_hdmi_audio_shutdown(struct device *dev, void *data) ++{ ++ struct drm_connector *connector = data; ++ const struct drm_connector_hdmi_audio_funcs *funcs = ++ connector->hdmi_audio.funcs; ++ ++ return funcs->shutdown(connector); ++} ++ ++static int drm_connector_hdmi_audio_mute_stream(struct device *dev, void *data, ++ bool enable, int direction) ++{ ++ struct drm_connector *connector = data; ++ const struct drm_connector_hdmi_audio_funcs *funcs = ++ connector->hdmi_audio.funcs; ++ ++ if (funcs->mute_stream) ++ return funcs->mute_stream(connector, enable, direction); ++ ++ return -ENOTSUPP; ++} ++ ++static int drm_connector_hdmi_audio_get_dai_id(struct snd_soc_component *comment, ++ struct device_node *endpoint, ++ void *data) ++{ ++ struct drm_connector *connector = data; ++ struct of_endpoint of_ep; ++ int ret; ++ ++ if (connector->hdmi_audio.dai_port < 0) ++ return -ENOTSUPP; ++ ++ ret = of_graph_parse_endpoint(endpoint, &of_ep); ++ if (ret < 0) ++ return ret; ++ ++ if (of_ep.port == connector->hdmi_audio.dai_port) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int drm_connector_hdmi_audio_get_eld(struct device *dev, void *data, ++ uint8_t *buf, size_t len) ++{ ++ struct drm_connector *connector = data; ++ ++ mutex_lock(&connector->eld_mutex); ++ memcpy(buf, connector->eld, min(sizeof(connector->eld), len)); ++ mutex_unlock(&connector->eld_mutex); ++ ++ return 0; ++} ++ ++static int drm_connector_hdmi_audio_hook_plugged_cb(struct device *dev, ++ void *data, ++ hdmi_codec_plugged_cb fn, ++ struct device *codec_dev) ++{ ++ struct drm_connector *connector = data; ++ ++ mutex_lock(&connector->hdmi_audio.lock); ++ ++ connector->hdmi_audio.plugged_cb = fn; ++ connector->hdmi_audio.plugged_cb_dev = codec_dev; ++ ++ fn(codec_dev, connector->hdmi_audio.last_state); ++ ++ mutex_unlock(&connector->hdmi_audio.lock); ++ ++ return 0; ++} ++ ++void drm_connector_hdmi_audio_plugged_notify(struct drm_connector *connector, ++ bool plugged) ++{ ++ mutex_lock(&connector->hdmi_audio.lock); ++ ++ connector->hdmi_audio.last_state = plugged; ++ ++ if (connector->hdmi_audio.plugged_cb && ++ connector->hdmi_audio.plugged_cb_dev) ++ connector->hdmi_audio.plugged_cb(connector->hdmi_audio.plugged_cb_dev, ++ connector->hdmi_audio.last_state); ++ ++ mutex_unlock(&connector->hdmi_audio.lock); ++} ++EXPORT_SYMBOL(drm_connector_hdmi_audio_plugged_notify); ++ ++static const struct hdmi_codec_ops drm_connector_hdmi_audio_ops = { ++ .audio_startup = drm_connector_hdmi_audio_startup, ++ .prepare = drm_connector_hdmi_audio_prepare, ++ .audio_shutdown = drm_connector_hdmi_audio_shutdown, ++ .mute_stream = drm_connector_hdmi_audio_mute_stream, ++ .get_eld = drm_connector_hdmi_audio_get_eld, ++ .get_dai_id = drm_connector_hdmi_audio_get_dai_id, ++ .hook_plugged_cb = drm_connector_hdmi_audio_hook_plugged_cb, ++}; ++ ++/** ++ * drm_connector_hdmi_audio_init - Initialize HDMI Codec device for the DRM connector ++ * @connector: A pointer to the connector to allocate codec for ++ * @hdmi_codec_dev: device to be used as a parent for the HDMI Codec ++ * @funcs: callbacks for this HDMI Codec ++ * @max_i2s_playback_channels: maximum number of playback I2S channels ++ * @spdif_playback: set if HDMI codec has S/PDIF playback port ++ * @dai_port: sound DAI port, -1 if it is not enabled ++ * ++ * Create a HDMI codec device to be used with the specified connector. ++ * ++ * Returns: ++ * Zero on success, error code on failure. ++ */ ++int drm_connector_hdmi_audio_init(struct drm_connector *connector, ++ struct device *hdmi_codec_dev, ++ const struct drm_connector_hdmi_audio_funcs *funcs, ++ unsigned int max_i2s_playback_channels, ++ bool spdif_playback, ++ int dai_port) ++{ ++ struct hdmi_codec_pdata codec_pdata = { ++ .ops = &drm_connector_hdmi_audio_ops, ++ .max_i2s_channels = max_i2s_playback_channels, ++ .i2s = !!max_i2s_playback_channels, ++ .spdif = spdif_playback, ++ .no_i2s_capture = true, ++ .no_spdif_capture = true, ++ .data = connector, ++ }; ++ struct platform_device *pdev; ++ ++ if (!funcs || ++ !funcs->prepare || ++ !funcs->shutdown) ++ return -EINVAL; ++ ++ connector->hdmi_audio.funcs = funcs; ++ connector->hdmi_audio.dai_port = dai_port; ++ ++ pdev = platform_device_register_data(hdmi_codec_dev, ++ HDMI_CODEC_DRV_NAME, ++ PLATFORM_DEVID_AUTO, ++ &codec_pdata, sizeof(codec_pdata)); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); ++ ++ connector->hdmi_audio.codec_pdev = pdev; ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_connector_hdmi_audio_init); +diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c +index ae6e71305..1383fa9ff 100644 +--- a/drivers/gpu/drm/drm_connector.c ++++ b/drivers/gpu/drm/drm_connector.c +@@ -33,6 +33,7 @@ + #include + #include + ++#include + #include + #include + +@@ -281,6 +282,7 @@ static int drm_connector_init_only(struct drm_device *dev, + mutex_init(&connector->eld_mutex); + mutex_init(&connector->edid_override_mutex); + mutex_init(&connector->hdmi.infoframes.lock); ++ mutex_init(&connector->hdmi_audio.lock); + connector->edid_blob_ptr = NULL; + connector->epoch_counter = 0; + connector->tile_blob_ptr = NULL; +@@ -714,6 +716,8 @@ void drm_connector_cleanup(struct drm_connector *connector) + DRM_CONNECTOR_REGISTERED)) + drm_connector_unregister(connector); + ++ platform_device_unregister(connector->hdmi_audio.codec_pdev); ++ + if (connector->privacy_screen) { + drm_privacy_screen_put(connector->privacy_screen); + connector->privacy_screen = NULL; +@@ -750,6 +754,7 @@ void drm_connector_cleanup(struct drm_connector *connector) + connector->funcs->atomic_destroy_state(connector, + connector->state); + ++ mutex_destroy(&connector->hdmi_audio.lock); + mutex_destroy(&connector->hdmi.infoframes.lock); + mutex_destroy(&connector->mutex); + +diff --git a/include/drm/display/drm_hdmi_audio_helper.h b/include/drm/display/drm_hdmi_audio_helper.h +new file mode 100644 +index 000000000..c9a6faef4 +--- /dev/null ++++ b/include/drm/display/drm_hdmi_audio_helper.h +@@ -0,0 +1,22 @@ ++/* SPDX-License-Identifier: MIT */ ++ ++#ifndef DRM_DISPLAY_HDMI_AUDIO_HELPER_H_ ++#define DRM_DISPLAY_HDMI_AUDIO_HELPER_H_ ++ ++#include ++ ++struct drm_connector; ++struct drm_connector_hdmi_audio_funcs; ++ ++struct device; ++ ++int drm_connector_hdmi_audio_init(struct drm_connector *connector, ++ struct device *hdmi_codec_dev, ++ const struct drm_connector_hdmi_audio_funcs *funcs, ++ unsigned int max_i2s_playback_channels, ++ bool spdif_playback, ++ int sound_dai_port); ++void drm_connector_hdmi_audio_plugged_notify(struct drm_connector *connector, ++ bool plugged); ++ ++#endif +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index d1be19242..1d4c27948 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -46,6 +46,8 @@ struct drm_property_blob; + struct drm_printer; + struct drm_privacy_screen; + struct edid; ++struct hdmi_codec_daifmt; ++struct hdmi_codec_params; + struct i2c_adapter; + + enum drm_connector_force { +@@ -1141,6 +1143,53 @@ struct drm_connector_state { + struct drm_connector_hdmi_state hdmi; + }; + ++struct drm_connector_hdmi_audio_funcs { ++ /** ++ * @startup: ++ * ++ * Called when ASoC starts an audio stream setup. The ++ * @startup() is optional. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ int (*startup)(struct drm_connector *connector); ++ ++ /** ++ * @prepare: ++ * Configures HDMI-encoder for audio stream. Can be called ++ * multiple times for each setup. Mandatory. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ int (*prepare)(struct drm_connector *connector, ++ struct hdmi_codec_daifmt *fmt, ++ struct hdmi_codec_params *hparms); ++ ++ /** ++ * @shutdown: ++ * ++ * Shut down the audio stream. Mandatory. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ void (*shutdown)(struct drm_connector *connector); ++ ++ /** ++ * @mute_stream: ++ * ++ * Mute/unmute HDMI audio stream. The @mute_stream callback is ++ * optional. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ int (*mute_stream)(struct drm_connector *connector, ++ bool enable, int direction); ++}; ++ + /** + * struct drm_connector_hdmi_funcs - drm_hdmi_connector control functions + */ +@@ -1660,6 +1709,68 @@ struct drm_cmdline_mode { + bool tv_mode_specified; + }; + ++/** ++ * struct drm_connector_hdmi_audio - DRM gemeric HDMI Codec-related structure ++ * ++ * HDMI drivers usually incorporate a HDMI Codec. This structure expresses the ++ * generic HDMI Codec as used by the DRM HDMI Codec framework. ++ */ ++struct drm_connector_hdmi_audio { ++ /** ++ * @funcs: ++ * ++ * Implementation of the HDMI codec functionality to be used by the DRM ++ * HDMI Codec framework. ++ */ ++ const struct drm_connector_hdmi_audio_funcs *funcs; ++ ++ /** ++ * @codec_pdev: ++ * ++ * Platform device created to hold the HDMI Codec. It will be ++ * automatically unregistered during drm_connector_cleanup(). ++ */ ++ struct platform_device *codec_pdev; ++ ++ /** ++ * @lock: ++ * ++ * Mutex to protect @last_state, @plugged_cb and @plugged_cb_dev. ++ */ ++ struct mutex lock; ++ ++ /** ++ * @plugged_cb: ++ * ++ * Callback to be called when the HDMI sink get plugged to or unplugged ++ * from this connector. This is assigned by the framework when ++ * requested by the ASoC code. ++ */ ++ void (*plugged_cb)(struct device *dev, bool plugged); ++ ++ /** ++ * @plugged_cb_dev: ++ * ++ * The data for @plugged_cb(). It is being provided by the ASoC. ++ */ ++ struct device *plugged_cb_dev; ++ ++ /** ++ * @last_state: ++ * ++ * Last plugged state recored by the framework. It is used to correctly ++ * report the state to @plugged_cb(). ++ */ ++ bool last_state; ++ ++ /** ++ * @dai_port: ++ * ++ * The port in DT that is used for the Codec DAI. ++ */ ++ int dai_port; ++}; ++ + /* + * struct drm_connector_hdmi - DRM Connector HDMI-related structure + */ +@@ -2121,6 +2232,11 @@ struct drm_connector { + * @hdmi: HDMI-related variable and properties. + */ + struct drm_connector_hdmi hdmi; ++ ++ /** ++ * @hdmi_audio: HDMI codec properties and non-DRM state. ++ */ ++ struct drm_connector_hdmi_audio hdmi_audio; + }; + + #define obj_to_connector(x) container_of(x, struct drm_connector, base) +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0029-drm-bridge-connector-add-support-for-HDMI-codec-fram.patch b/patch/kernel/archive/meson-6.13/0029-drm-bridge-connector-add-support-for-HDMI-codec-fram.patch new file mode 100644 index 000000000000..ad858893927f --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0029-drm-bridge-connector-add-support-for-HDMI-codec-fram.patch @@ -0,0 +1,259 @@ +From aa5221a8d7e10a15d017be6390aaaba0a5ec3b62 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 24 Dec 2024 03:47:56 +0200 +Subject: [PATCH 029/126] drm/bridge: connector: add support for HDMI codec + framework + +Add necessary glue code to be able to use new HDMI codec framework from +the DRM bridge drivers. The drm_bridge implements a limited set of the +hdmi_codec_ops interface, with the functions accepting both +drm_connector and drm_bridge instead of just a generic void pointer. + +This framework is integrated with the DRM HDMI Connector framework, but +can also be used for DisplayPort connectors. + +Reviewed-by: Maxime Ripard +Tested-by: Dave Stevenson +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/display/Kconfig | 1 + + .../gpu/drm/display/drm_bridge_connector.c | 99 ++++++++++++++++++- + include/drm/drm_bridge.h | 74 ++++++++++++++ + 3 files changed, 170 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig +index 80c1953ca..2619fa247 100644 +--- a/drivers/gpu/drm/display/Kconfig ++++ b/drivers/gpu/drm/display/Kconfig +@@ -15,6 +15,7 @@ if DRM_DISPLAY_HELPER + + config DRM_BRIDGE_CONNECTOR + bool ++ select DRM_DISPLAY_HDMI_AUDIO_HELPER + select DRM_DISPLAY_HDMI_STATE_HELPER + help + DRM connector implementation terminating DRM bridge chains. +diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c +index f6e0b6f1f..ed4225455 100644 +--- a/drivers/gpu/drm/display/drm_bridge_connector.c ++++ b/drivers/gpu/drm/display/drm_bridge_connector.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -387,6 +388,75 @@ + .write_infoframe = drm_bridge_connector_write_infoframe, + }; + ++static int drm_bridge_connector_audio_startup(struct drm_connector *connector) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ struct drm_bridge *bridge; ++ ++ bridge = bridge_connector->bridge_hdmi; ++ if (!bridge) ++ return -EINVAL; ++ ++ if (!bridge->funcs->hdmi_audio_startup) ++ return 0; ++ ++ return bridge->funcs->hdmi_audio_startup(connector, bridge); ++} ++ ++static int drm_bridge_connector_audio_prepare(struct drm_connector *connector, ++ struct hdmi_codec_daifmt *fmt, ++ struct hdmi_codec_params *hparms) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ struct drm_bridge *bridge; ++ ++ bridge = bridge_connector->bridge_hdmi; ++ if (!bridge) ++ return -EINVAL; ++ ++ return bridge->funcs->hdmi_audio_prepare(connector, bridge, fmt, hparms); ++} ++ ++static void drm_bridge_connector_audio_shutdown(struct drm_connector *connector) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ struct drm_bridge *bridge; ++ ++ bridge = bridge_connector->bridge_hdmi; ++ if (!bridge) ++ return; ++ ++ bridge->funcs->hdmi_audio_shutdown(connector, bridge); ++} ++ ++static int drm_bridge_connector_audio_mute_stream(struct drm_connector *connector, ++ bool enable, int direction) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ struct drm_bridge *bridge; ++ ++ bridge = bridge_connector->bridge_hdmi; ++ if (!bridge) ++ return -EINVAL; ++ ++ if (bridge->funcs->hdmi_audio_mute_stream) ++ return bridge->funcs->hdmi_audio_mute_stream(connector, bridge, ++ enable, direction); ++ else ++ return -ENOTSUPP; ++} ++ ++static const struct drm_connector_hdmi_audio_funcs drm_bridge_connector_hdmi_audio_funcs = { ++ .startup = drm_bridge_connector_audio_startup, ++ .prepare = drm_bridge_connector_audio_prepare, ++ .shutdown = drm_bridge_connector_audio_shutdown, ++ .mute_stream = drm_bridge_connector_audio_mute_stream, ++}; ++ + /* ----------------------------------------------------------------------------- + * Bridge Connector Initialisation + */ +@@ -490,6 +560,8 @@ + if (!connector->ycbcr_420_allowed) + supported_formats &= ~BIT(HDMI_COLORSPACE_YUV420); + ++ bridge = bridge_connector->bridge_hdmi; ++ + ret = drmm_connector_hdmi_init(drm, connector, + bridge_connector->bridge_hdmi->vendor, + bridge_connector->bridge_hdmi->product, +@@ -498,6 +570,24 @@ + connector_type, ddc, + supported_formats, + max_bpc); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ if (bridge->hdmi_audio_max_i2s_playback_channels || ++ bridge->hdmi_audio_spdif_playback) { ++ if (!bridge->funcs->hdmi_audio_prepare || ++ !bridge->funcs->hdmi_audio_shutdown) ++ return ERR_PTR(-EINVAL); ++ ++ ret = drm_connector_hdmi_audio_init(connector, ++ bridge->hdmi_audio_dev, ++ &drm_bridge_connector_hdmi_audio_funcs, ++ bridge->hdmi_audio_max_i2s_playback_channels, ++ bridge->hdmi_audio_spdif_playback, ++ bridge->hdmi_audio_dai_port); ++ if (ret) ++ return ERR_PTR(ret); ++ } + } else { + ret = drmm_connector_init(drm, connector, + &drm_bridge_connector_funcs, + +diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h +index e8d735b7f..4b84faf14 100644 +--- a/include/drm/drm_bridge.h ++++ b/include/drm/drm_bridge.h +@@ -41,6 +41,8 @@ struct drm_display_info; + struct drm_minor; + struct drm_panel; + struct edid; ++struct hdmi_codec_daifmt; ++struct hdmi_codec_params; + struct i2c_adapter; + + /** +@@ -676,6 +678,57 @@ struct drm_bridge_funcs { + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len); + ++ /** ++ * @hdmi_audio_startup: ++ * ++ * Called when ASoC starts an audio stream setup. The ++ * @hdmi_audio_startup() is optional. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ int (*hdmi_audio_startup)(struct drm_connector *connector, ++ struct drm_bridge *bridge); ++ ++ /** ++ * @prepare: ++ * Configures HDMI-encoder for audio stream. Can be called multiple ++ * times for each setup. Mandatory if HDMI audio is enabled in the ++ * bridge's configuration. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ int (*hdmi_audio_prepare)(struct drm_connector *connector, ++ struct drm_bridge *bridge, ++ struct hdmi_codec_daifmt *fmt, ++ struct hdmi_codec_params *hparms); ++ ++ /** ++ * @hdmi_audio_shutdown: ++ * ++ * Shut down the audio stream. Mandatory if HDMI audio is enabled in ++ * the bridge's configuration. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ void (*hdmi_audio_shutdown)(struct drm_connector *connector, ++ struct drm_bridge *bridge); ++ ++ /** ++ * @hdmi_audio_mute_stream: ++ * ++ * Mute/unmute HDMI audio stream. The @hdmi_audio_mute_stream callback ++ * is optional. ++ * ++ * Returns: ++ * 0 on success, a negative error code otherwise ++ */ ++ int (*hdmi_audio_mute_stream)(struct drm_connector *connector, ++ struct drm_bridge *bridge, ++ bool enable, int direction); ++ + /** + * @debugfs_init: + * +@@ -859,6 +912,27 @@ struct drm_bridge { + * @DRM_BRIDGE_OP_HDMI is set. + */ + unsigned int max_bpc; ++ ++ /** ++ * @hdmi_audio_dev: device to be used as a parent for the HDMI Codec ++ */ ++ struct device *hdmi_audio_dev; ++ ++ /** ++ * @hdmi_audio_max_i2s_playback_channels: maximum number of playback ++ * I2S channels for the HDMI codec ++ */ ++ int hdmi_audio_max_i2s_playback_channels; ++ ++ /** ++ * @hdmi_audio_spdif_playback: set if HDMI codec has S/PDIF playback port ++ */ ++ unsigned int hdmi_audio_spdif_playback : 1; ++ ++ /** ++ * @hdmi_audio_dai_port: sound DAI port, -1 if it is not enabled ++ */ ++ int hdmi_audio_dai_port; + }; + + static inline struct drm_bridge * +-- +2.48.1 diff --git a/patch/kernel/archive/meson-6.13/0030-drm-display-hdmi-implement-hotplug-functions.patch b/patch/kernel/archive/meson-6.13/0030-drm-display-hdmi-implement-hotplug-functions.patch new file mode 100644 index 000000000000..ed0b08ec8eb3 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0030-drm-display-hdmi-implement-hotplug-functions.patch @@ -0,0 +1,168 @@ +From 0cc588477fa9232320819c91ea437a8ec383ca10 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 24 Dec 2024 03:47:58 +0200 +Subject: [PATCH 030/126] drm/display/hdmi: implement hotplug functions + +The HDMI Connectors need to perform a variety of tasks when the HDMI +connector state changes. Such tasks include setting or invalidating CEC +address, notifying HDMI codec driver, updating scrambler data, etc. + +Implementing such tasks in a driver-specific callbacks is error prone. +Start implementing the generic helper function (currently handling only +the HDMI Codec framework) to be used by drivers utilizing HDMI Connector +framework. + +Reviewed-by: Maxime Ripard +Tested-by: Dave Stevenson +Signed-off-by: Dmitry Baryshkov +--- + drivers/gpu/drm/display/Kconfig | 1 + + .../gpu/drm/display/drm_hdmi_state_helper.c | 57 +++++++++++++++++++ + include/drm/display/drm_hdmi_state_helper.h | 5 ++ + include/drm/drm_connector.h | 16 ++++++ + 4 files changed, 79 insertions(+) + +diff --git a/drivers/gpu/drm/display/Kconfig b/drivers/gpu/drm/display/Kconfig +index 2619fa247..8d22b7627 100644 +--- a/drivers/gpu/drm/display/Kconfig ++++ b/drivers/gpu/drm/display/Kconfig +@@ -89,6 +89,7 @@ config DRM_DISPLAY_HDMI_HELPER + + config DRM_DISPLAY_HDMI_STATE_HELPER + bool ++ select DRM_DISPLAY_HDMI_AUDIO_HELPER + select DRM_DISPLAY_HDMI_HELPER + help + DRM KMS state helpers for HDMI. +diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c +index 80bf2829b..73498e18b 100644 +--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c ++++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c +@@ -5,6 +5,7 @@ + #include + #include + ++#include + #include + #include + +@@ -769,3 +770,59 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con + return ret; + } + EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe); ++ ++static void ++drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector, ++ enum drm_connector_status status) ++{ ++ const struct drm_edid *drm_edid; ++ ++ if (status == connector_status_disconnected) { ++ // TODO: also handle CEC and scramber, HDMI sink disconnected. ++ drm_connector_hdmi_audio_plugged_notify(connector, false); ++ } ++ ++ if (connector->hdmi.funcs->read_edid) ++ drm_edid = connector->hdmi.funcs->read_edid(connector); ++ else ++ drm_edid = drm_edid_read(connector); ++ ++ drm_edid_connector_update(connector, drm_edid); ++ ++ drm_edid_free(drm_edid); ++ ++ if (status == connector_status_connected) { ++ // TODO: also handle CEC and scramber, HDMI sink is now connected. ++ drm_connector_hdmi_audio_plugged_notify(connector, true); ++ } ++} ++ ++/** ++ * drm_atomic_helper_connector_hdmi_hotplug - Handle the hotplug event for the HDMI connector ++ * @connector: A pointer to the HDMI connector ++ * @status: Connection status ++ * ++ * This function should be called as a part of the .detect() / .detect_ctx() ++ * callbacks, updating the HDMI-specific connector's data. ++ */ ++void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector, ++ enum drm_connector_status status) ++{ ++ drm_atomic_helper_connector_hdmi_update(connector, status); ++} ++EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug); ++ ++/** ++ * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback ++ * @connector: A pointer to the HDMI connector ++ * ++ * This function implements the .force() callback for the HDMI connectors. It ++ * can either be used directly as the callback or should be called from within ++ * the .force() callback implementation to maintain the HDMI-specific ++ * connector's data. ++ */ ++void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector) ++{ ++ drm_atomic_helper_connector_hdmi_update(connector, connector->status); ++} ++EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force); +diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h +index d6d65da6d..9ae19f3ca 100644 +--- a/include/drm/display/drm_hdmi_state_helper.h ++++ b/include/drm/display/drm_hdmi_state_helper.h +@@ -8,6 +8,8 @@ struct drm_connector; + struct drm_connector_state; + struct hdmi_audio_infoframe; + ++enum drm_connector_status; ++ + void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector *connector, + struct drm_connector_state *new_conn_state); + +@@ -19,6 +21,9 @@ int drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector + int drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector); + int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector, + struct drm_atomic_state *state); ++void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector, ++ enum drm_connector_status status); ++void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector); + + enum drm_mode_status + drm_hdmi_connector_mode_valid(struct drm_connector *connector, +diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h +index 1d4c27948..f13d59737 100644 +--- a/include/drm/drm_connector.h ++++ b/include/drm/drm_connector.h +@@ -45,6 +45,7 @@ struct drm_property; + struct drm_property_blob; + struct drm_printer; + struct drm_privacy_screen; ++struct drm_edid; + struct edid; + struct hdmi_codec_daifmt; + struct hdmi_codec_params; +@@ -1247,6 +1248,21 @@ struct drm_connector_hdmi_funcs { + int (*write_infoframe)(struct drm_connector *connector, + enum hdmi_infoframe_type type, + const u8 *buffer, size_t len); ++ ++ /** ++ * @read_edid: ++ * ++ * This callback is used by the framework as a replacement for reading ++ * the EDID from connector->ddc. It is still recommended to provide ++ * connector->ddc instead of implementing this callback. Returned EDID ++ * should be freed via the drm_edid_free(). ++ * ++ * The @read_edid callback is optional. ++ * ++ * Returns: ++ * Valid EDID on success, NULL in case of failure. ++ */ ++ const struct drm_edid *(*read_edid)(struct drm_connector *connector); + }; + + /** +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0031-drm-bridge_connector-hook-drm_atomic_helper_connecto.patch b/patch/kernel/archive/meson-6.13/0031-drm-bridge_connector-hook-drm_atomic_helper_connecto.patch new file mode 100644 index 000000000000..5ccf37035fc6 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0031-drm-bridge_connector-hook-drm_atomic_helper_connecto.patch @@ -0,0 +1,115 @@ +From b44cbc9b0fa794d708ea9b19b3795efad856aea4 Mon Sep 17 00:00:00 2001 +From: Dmitry Baryshkov +Date: Tue, 24 Dec 2024 03:47:59 +0200 +Subject: [PATCH 031/126] drm/bridge_connector: hook + drm_atomic_helper_connector_hdmi_hotplug() + +Extend drm_bridge_connector code to read the EDID and use it to update +connector status if the bridge chain implements HDMI bridge. Performing +it from the generic location minimizes individual bridge's code and +enforces standard behaviour from all corresponding drivers. + +Reviewed-by: Maxime Ripard +Tested-by: Dave Stevenson +Signed-off-by: Dmitry Baryshkov +--- + .../gpu/drm/display/drm_bridge_connector.c | 39 +++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c +index ed4225455..e53f01681 100644 +--- a/drivers/gpu/drm/display/drm_bridge_connector.c ++++ b/drivers/gpu/drm/display/drm_bridge_connector.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -181,11 +182,15 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force) + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + struct drm_bridge *detect = bridge_connector->bridge_detect; ++ struct drm_bridge *hdmi = bridge_connector->bridge_hdmi; + enum drm_connector_status status; + + if (detect) { + status = detect->funcs->detect(detect); + ++ if (hdmi) ++ drm_atomic_helper_connector_hdmi_hotplug(connector, status); ++ + drm_bridge_connector_hpd_notify(connector, status); + } else { + switch (connector->connector_type) { +@@ -204,6 +209,16 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force) + return status; + } + ++static void drm_bridge_connector_force(struct drm_connector *connector) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ struct drm_bridge *hdmi = bridge_connector->bridge_hdmi; ++ ++ if (hdmi) ++ drm_atomic_helper_connector_hdmi_force(connector); ++} ++ + static void drm_bridge_connector_debugfs_init(struct drm_connector *connector, + struct dentry *root) + { +@@ -232,6 +247,7 @@ static void drm_bridge_connector_reset(struct drm_connector *connector) + static const struct drm_connector_funcs drm_bridge_connector_funcs = { + .reset = drm_bridge_connector_reset, + .detect = drm_bridge_connector_detect, ++ .force = drm_bridge_connector_force, + .fill_modes = drm_helper_probe_single_connector_modes, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +@@ -277,6 +293,14 @@ static int drm_bridge_connector_get_modes(struct drm_connector *connector) + to_drm_bridge_connector(connector); + struct drm_bridge *bridge; + ++ /* ++ * If there is a HDMI bridge, EDID has been updated as a part of ++ * the .detect(). Just update the modes here. ++ */ ++ bridge = bridge_connector->bridge_hdmi; ++ if (bridge) ++ return drm_edid_connector_add_modes(connector); ++ + /* + * If display exposes EDID, then we parse that in the normal way to + * build table of supported modes. +@@ -382,10 +406,25 @@ static int drm_bridge_connector_write_infoframe(struct drm_connector *connector, + return bridge->funcs->hdmi_write_infoframe(bridge, type, buffer, len); + } + ++static const struct drm_edid * ++drm_bridge_connector_read_edid(struct drm_connector *connector) ++{ ++ struct drm_bridge_connector *bridge_connector = ++ to_drm_bridge_connector(connector); ++ struct drm_bridge *bridge; ++ ++ bridge = bridge_connector->bridge_edid; ++ if (!bridge) ++ return NULL; ++ ++ return drm_bridge_edid_read(bridge, connector); ++} ++ + static const struct drm_connector_hdmi_funcs drm_bridge_connector_hdmi_funcs = { + .tmds_char_rate_valid = drm_bridge_connector_tmds_char_rate_valid, + .clear_infoframe = drm_bridge_connector_clear_infoframe, + .write_infoframe = drm_bridge_connector_write_infoframe, ++ .read_edid = drm_bridge_connector_read_edid, + }; + + static int drm_bridge_connector_audio_startup(struct drm_connector *connector) +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0032-ASoC-hdmi-codec-wire-up-the-.prepare-callback-also-f.patch b/patch/kernel/archive/meson-6.13/0032-ASoC-hdmi-codec-wire-up-the-.prepare-callback-also-f.patch new file mode 100644 index 000000000000..ebb8760feb55 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0032-ASoC-hdmi-codec-wire-up-the-.prepare-callback-also-f.patch @@ -0,0 +1,45 @@ +From d216ea886b38bca102a169fb39ccf046aceb2909 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 5 Jan 2025 17:06:09 +0100 +Subject: [PATCH 032/126] ASoC: hdmi-codec: wire up the .prepare callback also + for SPDIF DAI ops + +Commit 2fef64eec23a ("ASoC: hdmi-codec: Add a prepare hook") added a +prepare implementation. Back then the new callback was only integrated +with hdmi_codec_i2s_dai_ops (which is used by the I2S input code-path). +It was not added to hdmi_codec_spdif_dai_ops (which is used by the SPDIF +input code-path). + +With commit baf616647fe6 ("drm/connector: implement generic HDMI audio +helpers") the DRM subsystem has gained a helper framework which can be +used by HDMI controller drivers. HDMI controller drivers are often +tightly coupled with the hdmi-codec because of the so-called HDMI audio +infoframe (which is often managed by the display controller). + +To allow the new DRM HDMI audio framework to work with the hdmi-codec +driver for SPDIF inputs we also need to hook up the prepare callback to +hdmi_codec_spdif_dai_ops. Just hooking into the hw_params callback would +not be enough as hw_params (is called too early and) doesn't have access +to the HDMI audio infoframe contents. + +Suggested-by: Dmitry Baryshkov +Signed-off-by: Martin Blumenstingl +--- + sound/soc/codecs/hdmi-codec.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 69f98975e..f485f26b9 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -942,6 +942,7 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, ++ .prepare = hdmi_codec_prepare, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, + }; +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0033-dt-bindings-phy-meson8b-usb2-Add-support-for-reading.patch b/patch/kernel/archive/meson-6.13/0033-dt-bindings-phy-meson8b-usb2-Add-support-for-reading.patch new file mode 100644 index 000000000000..0a8e35c39b4a --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0033-dt-bindings-phy-meson8b-usb2-Add-support-for-reading.patch @@ -0,0 +1,47 @@ +From 2dedd3a561ef406e25d5e4feae01bdf724571cb4 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 16 Jun 2021 20:34:01 +0200 +Subject: [PATCH 033/126] 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 +--- + .../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 + +@@ -31,6 +35,11 @@ properties: + - const: usb_general + - const: usb + ++ '#gpio-cells': ++ const: 2 ++ ++ gpio-controller: true ++ + resets: + minItems: 1 + +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0034-phy-amlogic-meson8b-usb2-Add-support-for-reading-the.patch b/patch/kernel/archive/meson-6.13/0034-phy-amlogic-meson8b-usb2-Add-support-for-reading-the.patch new file mode 100644 index 000000000000..5d463485fa1d --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0034-phy-amlogic-meson8b-usb2-Add-support-for-reading-the.patch @@ -0,0 +1,102 @@ +From 772b4c33d2663316e13870da7ff6821c154c0b86 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 3 May 2020 21:40:27 +0200 +Subject: [PATCH 034/126] 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 +--- + drivers/phy/amlogic/phy-meson8b-usb2.c | 41 +++++++++++++++++++++++++- + 1 file changed, 40 insertions(+), 1 deletion(-) + +diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c +index a553231a9..3f96df0ad 100644 +--- a/drivers/phy/amlogic/phy-meson8b-usb2.c ++++ b/drivers/phy/amlogic/phy-meson8b-usb2.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -126,6 +127,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; + }; + +@@ -229,12 +231,43 @@ 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); ++ int ret; ++ ++ ret = regmap_test_bits(priv->regmap, REG_ADP_BC, REG_ADP_BC_ID_DIG); ++ ++ return ret > 0 ? 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.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) +@@ -273,6 +306,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0035-phy-amlogic-meson8b-usb2-register-child-USB-connecto.patch b/patch/kernel/archive/meson-6.13/0035-phy-amlogic-meson8b-usb2-register-child-USB-connecto.patch new file mode 100644 index 000000000000..20ec289f112f --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0035-phy-amlogic-meson8b-usb2-register-child-USB-connecto.patch @@ -0,0 +1,42 @@ +From 4177572ab73cd84a3a0a898bd6457ad05feef820 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Thu, 26 Dec 2024 12:29:36 +0100 +Subject: [PATCH 035/126] phy: amlogic: meson8b-usb2: register child (USB + connector) devices + +Populate the child devices/nodes which are typically USB connectors +with a compatible string (and additional properties) like +"gpio-usb-b-connector". + +Signed-off-by: Martin Blumenstingl +--- + drivers/phy/amlogic/phy-meson8b-usb2.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c +index 3f96df0ad..b09778d72 100644 +--- a/drivers/phy/amlogic/phy-meson8b-usb2.c ++++ b/drivers/phy/amlogic/phy-meson8b-usb2.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -312,6 +313,11 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev) + return ret; + } + ++ ret = devm_of_platform_populate(&pdev->dev); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to create child devices/connectors\n"); ++ + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0037-usb-common-usb-conn-gpio-Fall-back-to-polling-the-GP.patch b/patch/kernel/archive/meson-6.13/0037-usb-common-usb-conn-gpio-Fall-back-to-polling-the-GP.patch new file mode 100644 index 000000000000..2ab4443327c5 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0037-usb-common-usb-conn-gpio-Fall-back-to-polling-the-GP.patch @@ -0,0 +1,147 @@ +From 32395136d642ca19ca5951b90e844cc89aa06554 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 16 Jun 2021 21:07:50 +0200 +Subject: [PATCH 037/126] 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 +--- + 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 c84b4a700..8f53d62f9 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0038-ARM-dts-meson-Add-GPIO-controller-capabilities-to-th.patch b/patch/kernel/archive/meson-6.13/0038-ARM-dts-meson-Add-GPIO-controller-capabilities-to-th.patch new file mode 100644 index 000000000000..cc4292090947 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0038-ARM-dts-meson-Add-GPIO-controller-capabilities-to-th.patch @@ -0,0 +1,30 @@ +From 780b34e8fd8be792a43fa37e3c67808a934fb36f Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 16 Jun 2021 20:38:07 +0200 +Subject: [PATCH 038/126] 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 +--- + 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 28ec2c821..126f1de52 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0039-ARM-dts-meson8b-odroidc1-Enable-the-Micro-USB-OTG-co.patch b/patch/kernel/archive/meson-6.13/0039-ARM-dts-meson8b-odroidc1-Enable-the-Micro-USB-OTG-co.patch new file mode 100644 index 000000000000..655e2fcfa992 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0039-ARM-dts-meson8b-odroidc1-Enable-the-Micro-USB-OTG-co.patch @@ -0,0 +1,88 @@ +From 5d66a5d1cf353aefbb5c364ee4e78b5517519087 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 4 May 2020 00:16:00 +0200 +Subject: [PATCH 039/126] 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 +--- + .../arm/boot/dts/amlogic/meson8b-odroidc1.dts | 47 ++++++++++++++++++- + 1 file changed, 46 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts +index 1cd209320..e3841dff0 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 +@@ -361,8 +375,18 @@ &uart_AO { + pinctrl-names = "default"; + }; + +-&usb1_phy { ++&usb0 { + status = "okay"; ++ ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "peripheral"; ++ ++ port { ++ usb_to_musbcon: endpoint { ++ remote-endpoint = <&musbcon_to_usb>; ++ }; ++ }; + }; + + &usb1 { +@@ -379,3 +403,24 @@ hub@1 { + reset-gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_LOW>; + }; + }; ++ ++&usb0_phy { ++ status = "okay"; ++ ++ connector { ++ compatible = "gpio-usb-b-connector", "usb-b-connector"; ++ type = "micro"; ++ id-gpios = <&usb0_phy 0 GPIO_ACTIVE_HIGH>; ++ vbus-supply = <&usb0_vbus>; ++ ++ port { ++ musbcon_to_usb: endpoint { ++ remote-endpoint = <&usb_to_musbcon>; ++ }; ++ }; ++ }; ++}; ++ ++&usb1_phy { ++ status = "okay"; ++}; +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0040-dt-bindings-phy-Add-bindings-for-the-Amlogic-Meson-C.patch b/patch/kernel/archive/meson-6.13/0040-dt-bindings-phy-Add-bindings-for-the-Amlogic-Meson-C.patch new file mode 100644 index 000000000000..f431bfa14bb4 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0040-dt-bindings-phy-Add-bindings-for-the-Amlogic-Meson-C.patch @@ -0,0 +1,106 @@ +From 845ab28cac1ec8b9476f2c6e2a323d0abb375746 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 11 Oct 2021 23:37:19 +0200 +Subject: [PATCH 040/126] 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 +--- + .../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 ++ ++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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0041-phy-amlogic-Add-a-new-driver-for-the-CVBS-DAC-CVBS-P.patch b/patch/kernel/archive/meson-6.13/0041-phy-amlogic-Add-a-new-driver-for-the-CVBS-DAC-CVBS-P.patch new file mode 100644 index 000000000000..57ae5b613e7f --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0041-phy-amlogic-Add-a-new-driver-for-the-CVBS-DAC-CVBS-P.patch @@ -0,0 +1,447 @@ +From d4a997563d7bc721912eeaef39b0b60b05d9cd15 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 11 Oct 2021 23:05:25 +0200 +Subject: [PATCH 041/126] 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 +--- + 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 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++MODULE_DESCRIPTION("Amlogic Meson CVBS DAC driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0042-dt-bindings-display-meson-vpu-Add-the-CVBS-DAC-prope.patch b/patch/kernel/archive/meson-6.13/0042-dt-bindings-display-meson-vpu-Add-the-CVBS-DAC-prope.patch new file mode 100644 index 000000000000..9d133b96ac3e --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0042-dt-bindings-display-meson-vpu-Add-the-CVBS-DAC-prope.patch @@ -0,0 +1,49 @@ +From 0099da850b66a6da48963947db8ab01ba3d070ef Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 20 Oct 2021 22:19:25 +0200 +Subject: [PATCH 042/126] 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 +--- + .../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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0043-drm-meson-Add-support-for-using-a-PHY-for-the-CVBS-D.patch b/patch/kernel/archive/meson-6.13/0043-drm-meson-Add-support-for-using-a-PHY-for-the-CVBS-D.patch new file mode 100644 index 000000000000..b63213d90884 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0043-drm-meson-Add-support-for-using-a-PHY-for-the-CVBS-D.patch @@ -0,0 +1,318 @@ +From aa8ea3ebeff994c9382e464de50b484076d2fb33 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 22:06:53 +0200 +Subject: [PATCH 043/126] 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 +--- + 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 417f79829..09312aa44 100644 +--- a/drivers/gpu/drm/meson/Kconfig ++++ b/drivers/gpu/drm/meson/Kconfig +@@ -13,6 +13,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 + #include ++#include ++#include + + #include + #include +@@ -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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0045-dt-bindings-clock-meson8b-Add-the-RMII-reference-clo.patch b/patch/kernel/archive/meson-6.13/0045-dt-bindings-clock-meson8b-Add-the-RMII-reference-clo.patch new file mode 100644 index 000000000000..c56898039b2a --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0045-dt-bindings-clock-meson8b-Add-the-RMII-reference-clo.patch @@ -0,0 +1,39 @@ +From 697ec4f448604a5be23b3830023d6dfba33e480e Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 May 2020 23:16:07 +0200 +Subject: [PATCH 045/126] 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 +--- + .../devicetree/bindings/clock/amlogic,meson8-clkc.yaml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml +index ab73d4654..25e25c4dd 100644 +--- a/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml ++++ b/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml +@@ -21,7 +21,7 @@ properties: + + clocks: + minItems: 2 +- maxItems: 3 ++ maxItems: 4 + + clock-names: + minItems: 2 +@@ -29,6 +29,7 @@ properties: + - const: xtal + - const: ddr_pll + - const: clk_32k ++ - const: rmii_clk + + '#clock-cells': + const: 1 +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0046-dt-bindings-clock-meson8b-Add-the-Meson8-Ethernet-RM.patch b/patch/kernel/archive/meson-6.13/0046-dt-bindings-clock-meson8b-Add-the-Meson8-Ethernet-RM.patch new file mode 100644 index 000000000000..ca9268c5027c --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0046-dt-bindings-clock-meson8b-Add-the-Meson8-Ethernet-RM.patch @@ -0,0 +1,31 @@ +From e298ba59aa333fa87f346c6ee52400923f40789e Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 May 2020 23:23:49 +0200 +Subject: [PATCH 046/126] 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 +--- + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0047-clk-meson-meson8b-Add-the-Ethernet-RMII-clock-tree-o.patch b/patch/kernel/archive/meson-6.13/0047-clk-meson-meson8b-Add-the-Ethernet-RMII-clock-tree-o.patch new file mode 100644 index 000000000000..6801c5502c66 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0047-clk-meson-meson8b-Add-the-Ethernet-RMII-clock-tree-o.patch @@ -0,0 +1,166 @@ +From ef4754d6eaffa181edf0d3e0638cc7d0d7a9cc87 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 May 2020 23:25:13 +0200 +Subject: [PATCH 047/126] 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 +--- + 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 be2e3a5f8..0bb15c805 100644 +--- a/drivers/clk/meson/Kconfig ++++ b/drivers/clk/meson/Kconfig +@@ -59,6 +59,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 e4b474c5f..f65cb2e50 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" + +@@ -2677,6 +2678,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) + +@@ -2973,6 +3046,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[] = { +@@ -3601,6 +3678,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0048-dt-bindings-net-dwmac-meson-Add-the-Ethernet-clock-i.patch b/patch/kernel/archive/meson-6.13/0048-dt-bindings-net-dwmac-meson-Add-the-Ethernet-clock-i.patch new file mode 100644 index 000000000000..4b602cdf3764 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0048-dt-bindings-net-dwmac-meson-Add-the-Ethernet-clock-i.patch @@ -0,0 +1,52 @@ +From acde984210fa455dfee0d795e6d283a5fd130467 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 May 2020 23:37:35 +0200 +Subject: [PATCH 048/126] 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 +--- + .../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 d1e2bca3c..f3fa55a77 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0049-net-stmmac-dwmac-meson-Rename-the-SPEED_100-macro.patch b/patch/kernel/archive/meson-6.13/0049-net-stmmac-dwmac-meson-Rename-the-SPEED_100-macro.patch new file mode 100644 index 000000000000..c8a9462ed64b --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0049-net-stmmac-dwmac-meson-Rename-the-SPEED_100-macro.patch @@ -0,0 +1,44 @@ +From e8dc09ea1509d1da6e4280d8e6af220b76caac2c Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Dec 2021 04:07:05 +0100 +Subject: [PATCH 049/126] 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 +--- + 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 5469fa1b4..88640d214 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0050-net-stmmac-dwmac-meson-Manage-the-ethernet-clock.patch b/patch/kernel/archive/meson-6.13/0050-net-stmmac-dwmac-meson-Manage-the-ethernet-clock.patch new file mode 100644 index 000000000000..f5c88e9a199f --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0050-net-stmmac-dwmac-meson-Manage-the-ethernet-clock.patch @@ -0,0 +1,117 @@ +From 49ae9671a4efd7b3627e8b8b51f0a4fbf33499af Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Dec 2021 04:22:53 +0100 +Subject: [PATCH 050/126] 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 +--- + .../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 88640d214..20f9ac8e0 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 + */ + ++#include + #include + #include + #include +@@ -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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0051-net-stmmac-dwmac-meson-Initialize-all-known-PREG_ETH.patch b/patch/kernel/archive/meson-6.13/0051-net-stmmac-dwmac-meson-Initialize-all-known-PREG_ETH.patch new file mode 100644 index 000000000000..24a78aaf3b96 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0051-net-stmmac-dwmac-meson-Initialize-all-known-PREG_ETH.patch @@ -0,0 +1,76 @@ +From b41a030f16fd4a5318068e9c84bd6aa45378b065 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Dec 2021 04:18:30 +0100 +Subject: [PATCH 051/126] 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 +--- + .../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 20f9ac8e0..05df6dea8 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 + */ + ++#include + #include + #include + #include +@@ -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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0052-ARM-dts-meson-meson8-Add-the-clock-input-to-the-Ethe.patch b/patch/kernel/archive/meson-6.13/0052-ARM-dts-meson-meson8-Add-the-clock-input-to-the-Ethe.patch new file mode 100644 index 000000000000..ece9643b0fbc --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0052-ARM-dts-meson-meson8-Add-the-clock-input-to-the-Ethe.patch @@ -0,0 +1,34 @@ +From 783e699e2edf077aaf8bb0f4cc08b556045f3acb Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 May 2020 23:47:47 +0200 +Subject: [PATCH 052/126] 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 +--- + 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 847f7b1f1..4ec5a20bd 100644 +--- a/arch/arm/boot/dts/amlogic/meson8.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8.dtsi +@@ -615,8 +615,8 @@ temperature_calib: calib@1f4 { + }; + + ðmac { +- 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0053-dt-bindings-clock-meson8b-add-the-rtc_32k-oscillator.patch b/patch/kernel/archive/meson-6.13/0053-dt-bindings-clock-meson8b-add-the-rtc_32k-oscillator.patch new file mode 100644 index 000000000000..ad4c0825d673 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0053-dt-bindings-clock-meson8b-add-the-rtc_32k-oscillator.patch @@ -0,0 +1,38 @@ +From c1f095fb358625f87c7db92c9326980536de7ae2 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 Jan 2021 19:01:08 +0100 +Subject: [PATCH 053/126] 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 +--- + .../devicetree/bindings/clock/amlogic,meson8-clkc.yaml | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml +index 25e25c4dd..f3b11afeb 100644 +--- a/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml ++++ b/Documentation/devicetree/bindings/clock/amlogic,meson8-clkc.yaml +@@ -21,7 +21,7 @@ properties: + + clocks: + minItems: 2 +- maxItems: 4 ++ maxItems: 5 + + clock-names: + minItems: 2 +@@ -30,6 +30,7 @@ properties: + - const: ddr_pll + - const: clk_32k + - const: rmii_clk ++ - const: rtc_32k + + '#clock-cells': + const: 1 +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0054-clk-meson-meson8b-Add-the-mpeg_rtc_osc_sel-clock.patch b/patch/kernel/archive/meson-6.13/0054-clk-meson-meson8b-Add-the-mpeg_rtc_osc_sel-clock.patch new file mode 100644 index 000000000000..35ec01aed39b --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0054-clk-meson-meson8b-Add-the-mpeg_rtc_osc_sel-clock.patch @@ -0,0 +1,108 @@ +From 24058a06444031a213dc2d5ebb5e61c87a87ac3c Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 1 Jan 2021 18:55:05 +0100 +Subject: [PATCH 054/126] 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 +--- + 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 f65cb2e50..4cc8bb64d 100644 +--- a/drivers/clk/meson/meson8b.c ++++ b/drivers/clk/meson/meson8b.c +@@ -606,7 +606,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, +@@ -623,11 +640,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, + }, + }; + +@@ -3050,6 +3068,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[] = { +@@ -3265,6 +3284,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[] = { +@@ -3482,6 +3502,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[] = { +@@ -3682,6 +3703,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0055-ARM-dts-meson-Add-address-cells-size-cells-and-range.patch b/patch/kernel/archive/meson-6.13/0055-ARM-dts-meson-Add-address-cells-size-cells-and-range.patch new file mode 100644 index 000000000000..22652a097909 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0055-ARM-dts-meson-Add-address-cells-size-cells-and-range.patch @@ -0,0 +1,85 @@ +From 39471d5b55751b28dda10fd29a07dfdf7fe74f80 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 28 Aug 2021 18:50:10 +0200 +Subject: [PATCH 055/126] 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 +--- + 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 126f1de52..763ebfa6a 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 4ec5a20bd..f5aab5f46 100644 +--- a/arch/arm/boot/dts/amlogic/meson8.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8.dtsi +@@ -627,16 +627,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 0876611ce..9920175f0 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi +@@ -588,16 +588,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0063-ARM-dts-meson8-Add-the-PWM_C-DV9-and-PWM_D-pins.patch b/patch/kernel/archive/meson-6.13/0063-ARM-dts-meson8-Add-the-PWM_C-DV9-and-PWM_D-pins.patch new file mode 100644 index 000000000000..1ec5d8383e4e --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0063-ARM-dts-meson8-Add-the-PWM_C-DV9-and-PWM_D-pins.patch @@ -0,0 +1,45 @@ +From 1b2a4059f0c11276f3d95825f9b9b3baeb0824d7 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Thu, 22 Jul 2021 08:27:29 +0200 +Subject: [PATCH 063/126] 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 +--- + 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 f5aab5f46..5afd5a8c1 100644 +--- a/arch/arm/boot/dts/amlogic/meson8.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8.dtsi +@@ -481,6 +481,22 @@ gpio: bank@80 { + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0071-dt-bindings-display-meson-vpu-add-support-for-Meson8.patch b/patch/kernel/archive/meson-6.13/0071-dt-bindings-display-meson-vpu-add-support-for-Meson8.patch new file mode 100644 index 000000000000..792cc7ba246a --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0071-dt-bindings-display-meson-vpu-add-support-for-Meson8.patch @@ -0,0 +1,33 @@ +From f63aabef6675ee8af86628387635f0d8740784eb Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 22:16:15 +0200 +Subject: [PATCH 071/126] dt-bindings: display: meson-vpu: add support for + Meson8/8b/8m2 - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + .../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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0072-drm-meson-add-Meson8-Meson8b-Meson8m2-specific-vpu_c.patch b/patch/kernel/archive/meson-6.13/0072-drm-meson-add-Meson8-Meson8b-Meson8m2-specific-vpu_c.patch new file mode 100644 index 000000000000..4ec4d3faea00 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0072-drm-meson-add-Meson8-Meson8b-Meson8m2-specific-vpu_c.patch @@ -0,0 +1,39 @@ +From 2d2bcf68a39f25bbd83118e8e0c7c66929d8cf2a Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 21:50:45 +0200 +Subject: [PATCH 072/126] 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 +--- + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0073-drm-meson-Use-24-bits-per-pixel-for-the-framebuffer-.patch b/patch/kernel/archive/meson-6.13/0073-drm-meson-Use-24-bits-per-pixel-for-the-framebuffer-.patch new file mode 100644 index 000000000000..d0d1bacae0f8 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0073-drm-meson-Use-24-bits-per-pixel-for-the-framebuffer-.patch @@ -0,0 +1,69 @@ +From 57c3e01b8aff0282fce0efeb7e2258b91bd84825 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 26 Apr 2020 00:00:09 +0200 +Subject: [PATCH 073/126] 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 +DRM_FORMAT_RGB888 on older SoCs to get a working framebuffer console. + +Signed-off-by: Martin Blumenstingl +--- + drivers/gpu/drm/meson/meson_drv.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index 0f5a1a545..cab8d793f 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -161,6 +162,25 @@ static void meson_vpu_init(struct meson_drm *priv) + writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); + } + ++static void meson_drm_client_setup(struct meson_drm *priv) ++{ ++ /* ++ * 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 ++ * DRM_FORMAT_RGB888 on older SoCs 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)) ++ drm_client_setup_with_fourcc(priv->drm, DRM_FORMAT_RGB888); ++ else ++ drm_client_setup_with_fourcc(priv->drm, DRM_FORMAT_XRGB8888); ++} ++ + struct meson_drm_soc_attr { + struct meson_drm_soc_limits limits; + const struct soc_device_attribute *attrs; +@@ -355,7 +375,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + if (ret) + goto uninstall_irq; + +- drm_client_setup(drm, NULL); ++ meson_drm_client_setup(priv); + + return 0; + +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0074-drm-meson-Use-a-separate-list-of-supported-formats-f.patch b/patch/kernel/archive/meson-6.13/0074-drm-meson-Use-a-separate-list-of-supported-formats-f.patch new file mode 100644 index 000000000000..68ba2289b90d --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0074-drm-meson-Use-a-separate-list-of-supported-formats-f.patch @@ -0,0 +1,86 @@ +From ebaa86ee7054c5d0fb0e306c08b5f6ecf2cdb5a2 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 21:53:21 +0200 +Subject: [PATCH 074/126] 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 +--- + drivers/gpu/drm/meson/meson_plane.c | 33 ++++++++++++++++++++++++----- + 1 file changed, 28 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index b43ac6120..accd01495 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; + int ret; + +@@ -549,11 +564,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); ++ } ++ + ret = drm_universal_plane_init(priv->drm, plane, 0xFF, +- &meson_plane_funcs, +- supported_drm_formats, +- ARRAY_SIZE(supported_drm_formats), +- format_modifiers, ++ &meson_plane_funcs, drm_formats, ++ num_drm_formats, format_modifiers, + DRM_PLANE_TYPE_PRIMARY, "meson_primary_plane"); + if (ret) { + devm_kfree(priv->drm->dev, meson_plane); +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0075-drm-meson-Skip-VIU_OSD1_CTRL_STAT2-alpha-replace-val.patch b/patch/kernel/archive/meson-6.13/0075-drm-meson-Skip-VIU_OSD1_CTRL_STAT2-alpha-replace-val.patch new file mode 100644 index 000000000000..786264fdb68f --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0075-drm-meson-Skip-VIU_OSD1_CTRL_STAT2-alpha-replace-val.patch @@ -0,0 +1,52 @@ +From 4d8c945cffc6f507c1d40c48eac74fc631a96a90 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 31 Jan 2022 23:02:59 +0100 +Subject: [PATCH 075/126] 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 +--- + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0076-drm-meson-Enable-the-RGB-to-YUV-converter-on-Meson8-.patch b/patch/kernel/archive/meson-6.13/0076-drm-meson-Enable-the-RGB-to-YUV-converter-on-Meson8-.patch new file mode 100644 index 000000000000..de3db39ed3ce --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0076-drm-meson-Enable-the-RGB-to-YUV-converter-on-Meson8-.patch @@ -0,0 +1,35 @@ +From 47d00800f8512548a318d5f75d26084292d24de8 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 22:00:57 +0200 +Subject: [PATCH 076/126] 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 +--- + 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 accd01495..47d2f8328 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0077-drm-meson-Update-meson_vpu_init-to-work-with-Meson8-.patch b/patch/kernel/archive/meson-6.13/0077-drm-meson-Update-meson_vpu_init-to-work-with-Meson8-.patch new file mode 100644 index 000000000000..de198d6ee1db --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0077-drm-meson-Update-meson_vpu_init-to-work-with-Meson8-.patch @@ -0,0 +1,85 @@ +From 05f867788be55b8787e2655e25b8802cc3ae4ff3 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 22:03:27 +0200 +Subject: [PATCH 077/126] 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 +--- + 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 cab8d793f..063cf1e9d 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -138,28 +138,39 @@ static const 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_drm_client_setup(struct meson_drm *priv) +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0078-drm-meson-Describe-the-HDMI-PHY-frequency-limits-of-.patch b/patch/kernel/archive/meson-6.13/0078-drm-meson-Describe-the-HDMI-PHY-frequency-limits-of-.patch new file mode 100644 index 000000000000..8b8de6291959 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0078-drm-meson-Describe-the-HDMI-PHY-frequency-limits-of-.patch @@ -0,0 +1,43 @@ +From 732eb9a3dedb1a73b82532a3f9795e85ae16f566 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 23 Dec 2020 21:18:35 +0100 +Subject: [PATCH 078/126] drm/meson: Describe the HDMI PHY frequency limits of + Meson8b + +Meson8b only supports up to 1080p according to it's datasheet, even +though it's PLL register setup allows up to ~3GHz (same as on +Meson8/8m2). Limit the Meson8b SoC HDMI PHY frequency to 1.65GHz +(matching what's already present for GXL S805X and S805Y). + +Signed-off-by: Martin Blumenstingl +--- + drivers/gpu/drm/meson/meson_drv.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index 063cf1e9d..fed0494f6 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -198,13 +198,18 @@ 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 */ ++ /* ++ * 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0079-drm-meson-Update-the-HDMI-encoder-for-Meson8-8b-8m2.patch b/patch/kernel/archive/meson-6.13/0079-drm-meson-Update-the-HDMI-encoder-for-Meson8-8b-8m2.patch new file mode 100644 index 000000000000..cf540284d4b9 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0079-drm-meson-Update-the-HDMI-encoder-for-Meson8-8b-8m2.patch @@ -0,0 +1,144 @@ +From fb60d7c7bc0c258787eb9782fa5502144e75d669 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 6 Oct 2021 23:34:04 +0200 +Subject: [PATCH 079/126] 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 +--- + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0080-drm-meson-Only-set-ycbcr_420_allowed-on-64-bit-SoCs.patch b/patch/kernel/archive/meson-6.13/0080-drm-meson-Only-set-ycbcr_420_allowed-on-64-bit-SoCs.patch new file mode 100644 index 000000000000..204d829d1262 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0080-drm-meson-Only-set-ycbcr_420_allowed-on-64-bit-SoCs.patch @@ -0,0 +1,34 @@ +From 670c8c87620f515ddf7e165191bc2fd74cf20ecb Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Wed, 6 Oct 2021 23:37:44 +0200 +Subject: [PATCH 080/126] 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 +--- + 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0081-drm-meson-Make-the-HHI-registers-optional-WIP.patch b/patch/kernel/archive/meson-6.13/0081-drm-meson-Make-the-HHI-registers-optional-WIP.patch new file mode 100644 index 000000000000..7c66786ee698 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0081-drm-meson-Make-the-HHI-registers-optional-WIP.patch @@ -0,0 +1,100 @@ +From bd3bccce1d9d86031103679ed994e87db5e094b5 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Thu, 7 Oct 2021 19:09:49 +0200 +Subject: [PATCH 081/126] 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 +--- + 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 fed0494f6..3a95ba979 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -258,24 +258,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0082-drm-meson-Add-support-for-the-Meson8-8b-8m2-TranSwit.patch b/patch/kernel/archive/meson-6.13/0082-drm-meson-Add-support-for-the-Meson8-8b-8m2-TranSwit.patch new file mode 100644 index 000000000000..3b32b97f97cb --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0082-drm-meson-Add-support-for-the-Meson8-8b-8m2-TranSwit.patch @@ -0,0 +1,1951 @@ +From 84782927c20ed89c0094a1eae2042c4303b47074 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 5 May 2019 02:29:42 +0200 +Subject: [PATCH 082/126] drm/meson: Add support for the Meson8/8b/8m2 + TranSwitch HDMI transmitter - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + drivers/gpu/drm/meson/Kconfig | 11 + + drivers/gpu/drm/meson/Makefile | 1 + + drivers/gpu/drm/meson/meson_transwitch_hdmi.c | 1347 +++++++++++++++++ + drivers/gpu/drm/meson/meson_transwitch_hdmi.h | 543 +++++++ + 4 files changed, 1902 insertions(+) + create mode 100644 drivers/gpu/drm/meson/meson_transwitch_hdmi.c + create mode 100644 drivers/gpu/drm/meson/meson_transwitch_hdmi.h + +diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig +index 09312aa44..ba562c013 100644 +--- a/drivers/gpu/drm/meson/Kconfig ++++ b/drivers/gpu/drm/meson/Kconfig +@@ -28,3 +28,14 @@ config DRM_MESON_DW_MIPI_DSI + default y if DRM_MESON + select DRM_DW_MIPI_DSI + select GENERIC_PHY_MIPI_DPHY ++ ++config DRM_MESON_TRANSWITCH_HDMI ++ tristate "Amlogic Meson8/8b/8m2 TranSwitch HDMI 1.4 Controller support" ++ depends on ARM || COMPILE_TEST ++ depends on DRM_MESON ++ default y if DRM_MESON ++ select DRM_DISPLAY_HDMI_HELPER ++ select DRM_DISPLAY_HDMI_STATE_HELPER ++ select DRM_DISPLAY_HELPER ++ select REGMAP_MMIO ++ select SND_SOC_HDMI_CODEC if SND_SOC +diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile +index 43071bdbd..c44cb6c52 100644 +--- a/drivers/gpu/drm/meson/Makefile ++++ b/drivers/gpu/drm/meson/Makefile +@@ -7,3 +7,4 @@ meson-drm-y += meson_encoder_hdmi.o meson_encoder_dsi.o + obj-$(CONFIG_DRM_MESON) += meson-drm.o + obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o + obj-$(CONFIG_DRM_MESON_DW_MIPI_DSI) += meson_dw_mipi_dsi.o ++obj-$(CONFIG_DRM_MESON_TRANSWITCH_HDMI) += meson_transwitch_hdmi.o +diff --git a/drivers/gpu/drm/meson/meson_transwitch_hdmi.c b/drivers/gpu/drm/meson/meson_transwitch_hdmi.c +new file mode 100644 +index 000000000..ab2f2e83a +--- /dev/null ++++ b/drivers/gpu/drm/meson/meson_transwitch_hdmi.c +@@ -0,0 +1,1347 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021-2025 Martin Blumenstingl ++ * ++ * All registers and magic values are taken from Amlogic's GPL kernel sources: ++ * Copyright (C) 2010 Amlogic, Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++ ++#include "meson_transwitch_hdmi.h" ++ ++#define HDMI_ADDR_PORT 0x0 ++#define HDMI_DATA_PORT 0x4 ++#define HDMI_CTRL_PORT 0x8 ++ #define HDMI_CTRL_PORT_APB3_ERR_EN BIT(15) ++ ++struct meson_txc_hdmi { ++ struct regmap *regmap; ++ ++ struct clk *sys_clk; ++ ++ struct phy *phy; ++ bool phy_is_on; ++ ++ struct drm_bridge bridge; ++ struct drm_bridge *next_bridge; ++}; ++ ++#define bridge_to_meson_txc_hdmi(x) container_of(x, struct meson_txc_hdmi, bridge) ++ ++static const struct regmap_range meson_txc_hdmi_regmap_ranges[] = { ++ regmap_reg_range(0x0000, 0x07ff), ++ regmap_reg_range(0x8000, 0x800c), ++}; ++ ++static const struct regmap_access_table meson_txc_hdmi_regmap_access = { ++ .yes_ranges = meson_txc_hdmi_regmap_ranges, ++ .n_yes_ranges = ARRAY_SIZE(meson_txc_hdmi_regmap_ranges), ++}; ++ ++static int meson_txc_hdmi_reg_read(void *context, unsigned int addr, ++ unsigned int *data) ++{ ++ void __iomem *base = context; ++ ++ writel(addr, base + HDMI_ADDR_PORT); ++ writel(addr, base + HDMI_ADDR_PORT); ++ ++ *data = readl(base + HDMI_DATA_PORT); ++ ++ return 0; ++} ++ ++static int meson_txc_hdmi_reg_write(void *context, unsigned int addr, ++ unsigned int data) ++{ ++ void __iomem *base = context; ++ ++ writel(addr, base + HDMI_ADDR_PORT); ++ writel(addr, base + HDMI_ADDR_PORT); ++ ++ writel(data, base + HDMI_DATA_PORT); ++ ++ return 0; ++} ++ ++static const struct regmap_config meson_txc_hdmi_regmap_config = { ++ .reg_bits = 16, ++ .val_bits = 16, ++ .reg_stride = 1, ++ .reg_read = meson_txc_hdmi_reg_read, ++ .reg_write = meson_txc_hdmi_reg_write, ++ .rd_table = &meson_txc_hdmi_regmap_access, ++ .wr_table = &meson_txc_hdmi_regmap_access, ++ .max_register = HDMI_OTHER_RX_PACKET_INTR_CLR, ++ .fast_io = true, ++}; ++ ++static void meson_txc_hdmi_sys5_reset_assert(struct meson_txc_hdmi *priv) ++{ ++ /* A comment in the vendor driver says: bit5,6 is converted */ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH3_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH0_RST_IN); ++ usleep_range(10, 20); ++ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN); ++ usleep_range(10, 20); ++ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, ++ TX_SYS5_TX_SOFT_RESET_1_TX_PIXEL_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_I2S_RESET_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH2 | ++ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH1 | ++ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH0); ++ usleep_range(10, 20); ++} ++ ++static void meson_txc_hdmi_sys5_reset_deassert(struct meson_txc_hdmi *priv) ++{ ++ /* Release the resets except tmds_clk */ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, ++ TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN); ++ usleep_range(10, 20); ++ ++ /* Release the tmds_clk reset as well */ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, 0x0); ++ usleep_range(10, 20); ++ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_SR_RST); ++ usleep_range(10, 20); ++ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN); ++ usleep_range(10, 20); ++} ++ ++static void meson_txc_hdmi_config_hdcp_registers(struct meson_txc_hdmi *priv) ++{ ++ regmap_write(priv->regmap, TX_HDCP_CONFIG0, ++ FIELD_PREP(TX_HDCP_CONFIG0_ROM_ENCRYPT_OFF, 0x3)); ++ regmap_write(priv->regmap, TX_HDCP_MEM_CONFIG, 0x0); ++ regmap_write(priv->regmap, TX_HDCP_ENCRYPT_BYTE, 0x0); ++ ++ regmap_write(priv->regmap, TX_HDCP_MODE, TX_HDCP_MODE_CLEAR_AVMUTE); ++ ++ regmap_write(priv->regmap, TX_HDCP_MODE, TX_HDCP_MODE_ESS_CONFIG); ++} ++ ++static void meson_txc_hdmi_config_color_space(struct meson_txc_hdmi *priv, ++ unsigned int input_bus_format, ++ struct drm_connector_hdmi_state *hdmi, ++ enum hdmi_colorimetry colorimetry) ++{ ++ unsigned int input_color_format, input_color_depth; ++ unsigned int output_color_format, output_color_depth, output_color_range; ++ ++ switch (input_bus_format) { ++ case MEDIA_BUS_FMT_UYVY12_1X24: ++ case MEDIA_BUS_FMT_UYVY10_1X20: ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ input_color_format = TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_YCBCR422; ++ break; ++ case MEDIA_BUS_FMT_YUV16_1X48: ++ case MEDIA_BUS_FMT_YUV12_1X36: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ input_color_format = TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_YCBCR444; ++ break; ++ case MEDIA_BUS_FMT_RGB161616_1X48: ++ case MEDIA_BUS_FMT_RGB121212_1X36: ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ default: ++ input_color_format = TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_RGB444; ++ break; ++ } ++ ++ switch (input_bus_format) { ++ case MEDIA_BUS_FMT_YUV16_1X48: ++ case MEDIA_BUS_FMT_RGB161616_1X48: ++ input_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_48_BIT; ++ break; ++ case MEDIA_BUS_FMT_UYVY12_1X24: ++ case MEDIA_BUS_FMT_YUV12_1X36: ++ case MEDIA_BUS_FMT_RGB121212_1X36: ++ input_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_36_BIT; ++ break; ++ case MEDIA_BUS_FMT_UYVY10_1X20: ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ input_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_30_BIT; ++ break; ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ default: ++ input_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_24_BIT; ++ break; ++ } ++ ++ switch (hdmi->output_format) { ++ case HDMI_COLORSPACE_YUV422: ++ output_color_format = TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_YCBCR422; ++ break; ++ case HDMI_COLORSPACE_YUV444: ++ output_color_format = TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_YCBCR444; ++ break; ++ case HDMI_COLORSPACE_RGB: ++ default: ++ output_color_format = TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_RGB444; ++ break; ++ } ++ ++ switch (hdmi->output_bpc) { ++ case 16: ++ output_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_48_BIT; ++ break; ++ case 12: ++ output_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_36_BIT; ++ break; ++ case 10: ++ output_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_30_BIT; ++ break; ++ case 8: ++ default: ++ output_color_depth = TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_24_BIT; ++ break; ++ } ++ ++ regmap_write(priv->regmap, TX_VIDEO_DTV_MODE, ++ FIELD_PREP(TX_VIDEO_DTV_MODE_COLOR_DEPTH, ++ output_color_depth)); ++ ++ regmap_write(priv->regmap, TX_VIDEO_DTV_OPTION_L, ++ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_FORMAT, ++ output_color_format) | ++ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_FORMAT, ++ input_color_format) | ++ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_DEPTH, ++ output_color_depth) | ++ FIELD_PREP(TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_DEPTH, ++ input_color_depth)); ++ ++ if (hdmi->is_limited_range) ++ output_color_range = TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_235; ++ else ++ output_color_range = TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_0_255; ++ ++ regmap_write(priv->regmap, TX_VIDEO_DTV_OPTION_H, ++ FIELD_PREP(TX_VIDEO_DTV_OPTION_H_OUTPUT_COLOR_RANGE, ++ output_color_range) | ++ FIELD_PREP(TX_VIDEO_DTV_OPTION_H_INPUT_COLOR_RANGE, ++ TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_0_255)); ++ ++ if (colorimetry == HDMI_COLORIMETRY_ITU_601) { ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B0, 0x2f); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B1, 0x1d); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R0, 0x8b); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R1, 0x4c); ++ ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB0, 0x18); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB1, 0x58); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR0, 0xd0); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR1, 0xb6); ++ } else { ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B0, 0x7b); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_B1, 0x12); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R0, 0x6c); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_R1, 0x36); ++ ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB0, 0xf2); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CB1, 0x2f); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR0, 0xd4); ++ regmap_write(priv->regmap, TX_VIDEO_CSC_COEFF_CR1, 0x77); ++ } ++} ++ ++static void meson_txc_hdmi_set_serializer_clock(struct meson_txc_hdmi *priv, ++ enum hdmi_colorimetry colorimetry, ++ u8 cea_mode, ++ unsigned int output_bpc) ++{ ++ u8 ts_sys1_pll; ++ ++ /* Serializer Internal clock setting */ ++ if (colorimetry == HDMI_COLORIMETRY_ITU_601) ++ ts_sys1_pll = 0x24; ++ else if (cea_mode == 16 && output_bpc == 10) ++ ts_sys1_pll = 0x12; ++ else ++ ts_sys1_pll = 0x22; ++ ++ regmap_write(priv->regmap, TX_SYS1_PLL, ts_sys1_pll); ++} ++ ++static void meson_txc_hdmi_reconfig_packet_setting(struct meson_txc_hdmi *priv, ++ u8 cea_mode) ++{ ++ u8 alloc_active2, alloc_eof1, alloc_sof1, alloc_sof2; ++ ++ regmap_write(priv->regmap, TX_PACKET_CONTROL_1, ++ FIELD_PREP(TX_PACKET_CONTROL_1_PACKET_START_LATENCY, 58)); ++ regmap_write(priv->regmap, TX_PACKET_CONTROL_2, ++ TX_PACKET_CONTROL_2_HORIZONTAL_GC_PACKET_TRANSPORT_EN); ++ ++ switch (cea_mode) { ++ case 31: ++ /* 1920x1080p50 */ ++ alloc_active2 = 0x12; ++ alloc_eof1 = 0x10; ++ alloc_sof1 = 0xb6; ++ alloc_sof2 = 0x11; ++ break; ++ case 93: ++ /* 3840x2160p24 */ ++ alloc_active2 = 0x12; ++ alloc_eof1 = 0x47; ++ alloc_sof1 = 0xf8; ++ alloc_sof2 = 0x52; ++ break; ++ case 94: ++ /* 3840x2160p25 */ ++ alloc_active2 = 0x12; ++ alloc_eof1 = 0x44; ++ alloc_sof1 = 0xda; ++ alloc_sof2 = 0x52; ++ break; ++ case 95: ++ /* 3840x2160p30 */ ++ alloc_active2 = 0x0f; ++ alloc_eof1 = 0x3a; ++ alloc_sof1 = 0x60; ++ alloc_sof2 = 0x52; ++ break; ++ case 98: ++ /* 4096x2160p24 */ ++ alloc_active2 = 0x12; ++ alloc_eof1 = 0x47; ++ alloc_sof1 = 0xf8; ++ alloc_sof2 = 0x52; ++ break; ++ default: ++ /* Disable the special packet settings only */ ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_ACTIVE_1, 0x00); ++ return; ++ } ++ ++ /* ++ * The vendor driver says: manually configure these register to get ++ * stable video timings. ++ */ ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_ACTIVE_1, 0x01); ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_ACTIVE_2, alloc_active2); ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_EOF_1, alloc_eof1); ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_EOF_2, 0x12); ++ regmap_write(priv->regmap, TX_CORE_ALLOC_VSYNC_0, 0x01); ++ regmap_write(priv->regmap, TX_CORE_ALLOC_VSYNC_1, 0x00); ++ regmap_write(priv->regmap, TX_CORE_ALLOC_VSYNC_2, 0x0a); ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_SOF_1, alloc_sof1); ++ regmap_write(priv->regmap, TX_PACKET_ALLOC_SOF_2, alloc_sof2); ++ regmap_set_bits(priv->regmap, TX_PACKET_CONTROL_1, ++ TX_PACKET_CONTROL_1_FORCE_PACKET_TIMING); ++} ++ ++static int meson_txc_hdmi_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ struct meson_txc_hdmi *priv = bridge->driver_private; ++ ++ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ++ drm_err(bridge->dev, ++ "DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is not set but needed\n"); ++ return -EINVAL; ++ } ++ ++ return drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge, ++ flags); ++} ++ ++/* Can return a maximum of 11 possible output formats for a mode/connector */ ++#define MAX_OUTPUT_SEL_FORMATS 11 ++ ++static u32 * ++meson_txc_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state, ++ unsigned int *num_output_fmts) ++{ ++ struct drm_connector *conn = conn_state->connector; ++ struct drm_display_info *info = &conn->display_info; ++ u8 max_bpc = conn_state->max_requested_bpc; ++ unsigned int i = 0; ++ u32 *output_fmts; ++ ++ *num_output_fmts = 0; ++ ++ output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts), ++ GFP_KERNEL); ++ if (!output_fmts) ++ return NULL; ++ ++ /* Avoid negotiating with ourselves if we're the first or only bridge */ ++ if (list_is_singular(&bridge->encoder->bridge_chain) || ++ list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) { ++ *num_output_fmts = 1; ++ output_fmts[0] = MEDIA_BUS_FMT_FIXED; ++ ++ return output_fmts; ++ } ++ ++ /* ++ * Order bus formats from 16bit to 8bit and from YUV422 to RGB ++ * if supported. In any case the default RGB888 format is added ++ */ ++ ++ /* Default 8bit RGB fallback */ ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ ++ if (max_bpc >= 16 && info->bpc == 16) { ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) ++ output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; ++ ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; ++ } ++ ++ if (max_bpc >= 12 && info->bpc >= 12) { ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) ++ output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; ++ ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) ++ output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; ++ ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ } ++ ++ if (max_bpc >= 10 && info->bpc >= 10) { ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) ++ output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; ++ ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) ++ output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; ++ ++ output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ } ++ ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) ++ output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; ++ ++ if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) ++ output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; ++ ++ *num_output_fmts = i; ++ ++ return output_fmts; ++} ++ ++/* Can return a maximum of 3 possible input formats for an output format */ ++#define MAX_INPUT_SEL_FORMATS 3 ++ ++static u32 * ++meson_txc_hdmi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state, ++ u32 output_fmt, ++ unsigned int *num_input_fmts) ++{ ++ u32 *input_fmts; ++ unsigned int i = 0; ++ ++ *num_input_fmts = 0; ++ ++ input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), ++ GFP_KERNEL); ++ if (!input_fmts) ++ return NULL; ++ ++ switch (output_fmt) { ++ /* If MEDIA_BUS_FMT_FIXED is tested, return default bus format */ ++ case MEDIA_BUS_FMT_FIXED: ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ break; ++ ++ /* 8bit */ ++ case MEDIA_BUS_FMT_RGB888_1X24: ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; ++ break; ++ case MEDIA_BUS_FMT_YUV8_1X24: ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ break; ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB888_1X24; ++ break; ++ ++ /* 10bit */ ++ case MEDIA_BUS_FMT_RGB101010_1X30: ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; ++ break; ++ case MEDIA_BUS_FMT_YUV10_1X30: ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ break; ++ case MEDIA_BUS_FMT_UYVY10_1X20: ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; ++ break; ++ ++ /* 12bit */ ++ case MEDIA_BUS_FMT_RGB121212_1X36: ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; ++ break; ++ case MEDIA_BUS_FMT_YUV12_1X36: ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ break; ++ case MEDIA_BUS_FMT_UYVY12_1X24: ++ input_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; ++ break; ++ ++ /* 16bit */ ++ case MEDIA_BUS_FMT_RGB161616_1X48: ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; ++ break; ++ case MEDIA_BUS_FMT_YUV16_1X48: ++ input_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; ++ input_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; ++ break; ++ } ++ ++ *num_input_fmts = i; ++ ++ if (*num_input_fmts == 0) { ++ kfree(input_fmts); ++ input_fmts = NULL; ++ } ++ ++ return input_fmts; ++} ++ ++static void meson_txc_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ struct drm_atomic_state *state = old_bridge_state->base.state; ++ struct drm_connector_state *conn_state; ++ struct drm_bridge_state *bridge_state; ++ enum hdmi_colorimetry colorimetry; ++ struct drm_crtc_state *crtc_state; ++ struct drm_connector *connector; ++ unsigned int i; ++ u8 cea_mode; ++ ++ bridge_state = drm_atomic_get_new_bridge_state(state, bridge); ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!connector)) ++ return; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, connector); ++ if (WARN_ON(!conn_state)) ++ return; ++ ++ if (connector->display_info.is_hdmi) { ++ crtc_state = drm_atomic_get_new_crtc_state(state, ++ conn_state->crtc); ++ if (WARN_ON(!crtc_state)) ++ return; ++ ++ cea_mode = drm_match_cea_mode(&crtc_state->adjusted_mode); ++ ++ switch (cea_mode) { ++ case 2 ... 3: ++ case 6 ... 7: ++ case 17 ... 18: ++ case 21 ... 22: ++ colorimetry = HDMI_COLORIMETRY_ITU_601; ++ break; ++ ++ default: ++ colorimetry = HDMI_COLORIMETRY_ITU_709; ++ break; ++ } ++ } else { ++ cea_mode = 0; ++ colorimetry = HDMI_COLORIMETRY_NONE; ++ } ++ ++ drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); ++ ++ meson_txc_hdmi_sys5_reset_assert(priv); ++ ++ meson_txc_hdmi_config_hdcp_registers(priv); ++ ++ if (cea_mode == 39) ++ regmap_write(priv->regmap, TX_VIDEO_DTV_TIMING, 0x0); ++ else ++ regmap_write(priv->regmap, TX_VIDEO_DTV_TIMING, ++ TX_VIDEO_DTV_TIMING_DISABLE_VIC39_CORRECTION); ++ ++ regmap_write(priv->regmap, TX_CORE_DATA_CAPTURE_2, ++ TX_CORE_DATA_CAPTURE_2_INTERNAL_PACKET_ENABLE); ++ regmap_write(priv->regmap, TX_CORE_DATA_MONITOR_1, ++ TX_CORE_DATA_MONITOR_1_LANE0 | ++ FIELD_PREP(TX_CORE_DATA_MONITOR_1_SELECT_LANE0, 0x7)); ++ regmap_write(priv->regmap, TX_CORE_DATA_MONITOR_2, ++ FIELD_PREP(TX_CORE_DATA_MONITOR_2_MONITOR_SELECT, 0x2)); ++ ++ if (connector->display_info.is_hdmi) ++ regmap_write(priv->regmap, TX_TMDS_MODE, ++ TX_TMDS_MODE_FORCED_HDMI | ++ TX_TMDS_MODE_HDMI_CONFIG); ++ else ++ regmap_write(priv->regmap, TX_TMDS_MODE, ++ TX_TMDS_MODE_FORCED_HDMI); ++ ++ regmap_write(priv->regmap, TX_SYS4_CONNECT_SEL_1, 0x0); ++ ++ /* ++ * Set tmds_clk pattern to be "0000011111" before being sent to AFE ++ * clock channel. ++ */ ++ regmap_write(priv->regmap, TX_SYS4_CK_INV_VIDEO, ++ TX_SYS4_CK_INV_VIDEO_TMDS_CLK_PATTERN); ++ ++ regmap_write(priv->regmap, TX_SYS5_FIFO_CONFIG, ++ TX_SYS5_FIFO_CONFIG_CLK_CHANNEL3_OUTPUT_ENABLE | ++ TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL2_ENABLE | ++ TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL1_ENABLE | ++ TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL0_ENABLE); ++ ++ meson_txc_hdmi_config_color_space(priv, ++ bridge_state->input_bus_cfg.format, ++ &conn_state->hdmi, ++ colorimetry); ++ ++ meson_txc_hdmi_sys5_reset_deassert(priv); ++ ++ meson_txc_hdmi_set_serializer_clock(priv, colorimetry, cea_mode, ++ conn_state->hdmi.output_bpc); ++ meson_txc_hdmi_reconfig_packet_setting(priv, cea_mode); ++ ++ /* all resets need to be applied twice */ ++ for (i = 0; i < 2; i++) { ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, ++ TX_SYS5_TX_SOFT_RESET_1_TX_PIXEL_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_I2S_RESET_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH2 | ++ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH1 | ++ TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH0); ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH3_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_CH0_RST_IN | ++ TX_SYS5_TX_SOFT_RESET_2_HDMI_SR_RST | ++ TX_SYS5_TX_SOFT_RESET_2_TX_DDC_HDCP_RSTN | ++ TX_SYS5_TX_SOFT_RESET_2_TX_DDC_EDID_RSTN | ++ TX_SYS5_TX_SOFT_RESET_2_TX_DIG_RESET_N_CH3); ++ usleep_range(5000, 10000); ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, 0x00); ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_2, 0x00); ++ usleep_range(5000, 10000); ++ } ++ ++ if (!priv->phy_is_on) { ++ int ret; ++ ++ ret = phy_power_on(priv->phy); ++ if (ret) ++ drm_err(bridge->dev, "Failed to turn on PHY\n"); ++ else ++ priv->phy_is_on = true; ++ } ++} ++ ++static void meson_txc_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_bridge_state) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ ++ if (priv->phy_is_on) { ++ int ret; ++ ++ ret = phy_power_off(priv->phy); ++ if (ret) ++ drm_err(bridge->dev, "Failed to turn off PHY\n"); ++ else ++ priv->phy_is_on = false; ++ } ++} ++ ++static enum drm_mode_status ++meson_txc_hdmi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ unsigned long long rate; ++ ++ if (mode->hdisplay > 3840) ++ return MODE_BAD_HVALUE; ++ ++ rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); ++ if (rate == 0) ++ return MODE_NOCLOCK; ++ ++ return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate); ++} ++ ++static enum drm_connector_status meson_txc_hdmi_bridge_detect(struct drm_bridge *bridge) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ ++ if (regmap_test_bits(priv->regmap, TX_HDCP_ST_EDID_STATUS, ++ TX_HDCP_ST_EDID_STATUS_HPD_STATUS) > 0) ++ return connector_status_connected; ++ ++ return connector_status_disconnected; ++} ++ ++static int meson_txc_hdmi_get_edid_block(void *data, u8 *buf, unsigned int block, ++ size_t len) ++{ ++ unsigned int i, regval, start = block * EDID_LENGTH; ++ struct meson_txc_hdmi *priv = data; ++ int ret; ++ ++ /* Start the DDC transaction */ ++ regmap_clear_bits(priv->regmap, TX_HDCP_EDID_CONFIG, ++ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG); ++ regmap_set_bits(priv->regmap, TX_HDCP_EDID_CONFIG, ++ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, ++ TX_HDCP_ST_EDID_STATUS, ++ regval, ++ (regval & TX_HDCP_ST_EDID_STATUS_EDID_DATA_READY), ++ 1000, 200000); ++ ++ regmap_clear_bits(priv->regmap, TX_HDCP_EDID_CONFIG, ++ TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG); ++ ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < len; i++) { ++ regmap_read(priv->regmap, TX_RX_EDID_OFFSET + start + i, ++ ®val); ++ buf[i] = regval; ++ } ++ ++ return 0; ++} ++ ++static const struct drm_edid *meson_txc_hdmi_bridge_edid_read(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ const struct drm_edid *drm_edid; ++ ++ drm_edid = drm_edid_read_custom(connector, ++ meson_txc_hdmi_get_edid_block, priv); ++ if (!drm_edid) { ++ drm_dbg(priv->bridge.dev, "Failed to get EDID\n"); ++ return NULL; ++ } ++ ++ return drm_edid; ++} ++ ++static enum drm_mode_status ++meson_txc_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ unsigned long long tmds_rate) ++{ ++ /* 297 MHz for 4k@30 mode (HDMI 1.4) */ ++ if (tmds_rate > 297000000) ++ return MODE_CLOCK_HIGH; ++ ++ return MODE_OK; ++} ++ ++static void meson_txc_hdmi_infoframe_set(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type, ++ const u8 *buffer, size_t len, ++ bool enable) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ unsigned int i, tx_pkt_reg; ++ ++ switch (type) { ++ case HDMI_INFOFRAME_TYPE_VENDOR: ++ tx_pkt_reg = TX_PKT_REG_VEND_INFO_BASE_ADDR; ++ break; ++ case HDMI_INFOFRAME_TYPE_AVI: ++ tx_pkt_reg = TX_PKT_REG_AVI_INFO_BASE_ADDR; ++ break; ++ case HDMI_INFOFRAME_TYPE_SPD: ++ tx_pkt_reg = TX_PKT_REG_SPD_INFO_BASE_ADDR; ++ break; ++ case HDMI_INFOFRAME_TYPE_AUDIO: ++ tx_pkt_reg = TX_PKT_REG_AUDIO_INFO_BASE_ADDR; ++ break; ++ default: ++ drm_dbg_driver(bridge->dev, "Unsupported HDMI InfoFrame %x\n", ++ type); ++ return; ++ } ++ ++ /* Write the data bytes by starting at register offset 1 */ ++ for (i = HDMI_INFOFRAME_HEADER_SIZE; i < len; i++) ++ regmap_write(priv->regmap, ++ tx_pkt_reg + i - HDMI_INFOFRAME_HEADER_SIZE + 1, ++ buffer[i]); ++ ++ /* Zero all remaining data bytes */ ++ for (; i < 0x1c; i++) ++ regmap_write(priv->regmap, tx_pkt_reg + i, 0x00); ++ ++ /* Write the header (which we skipped above) */ ++ regmap_write(priv->regmap, tx_pkt_reg + 0x00, buffer[3]); ++ regmap_write(priv->regmap, tx_pkt_reg + 0x1c, buffer[0]); ++ regmap_write(priv->regmap, tx_pkt_reg + 0x1d, buffer[1]); ++ regmap_write(priv->regmap, tx_pkt_reg + 0x1e, buffer[2]); ++ ++ regmap_write(priv->regmap, tx_pkt_reg + 0x1f, enable ? 0xff : 0x00); ++} ++ ++static int meson_txc_hdmi_clear_infoframe(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type) ++{ ++ u8 buffer[HDMI_INFOFRAME_HEADER_SIZE] = { 0 }; ++ ++ meson_txc_hdmi_infoframe_set(bridge, type, buffer, ++ HDMI_INFOFRAME_HEADER_SIZE, false); ++ ++ return 0; ++} ++ ++static int meson_txc_hdmi_write_infoframe(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type, ++ const u8 *buffer, size_t len) ++{ ++ meson_txc_hdmi_infoframe_set(bridge, type, buffer, len, true); ++ ++ return 0; ++} ++ ++static u32 meson_txc_hdmi_hdmi_codec_calc_audio_n(struct hdmi_codec_params *hparms) ++{ ++ u32 audio_n; ++ ++ if ((hparms->sample_rate % 44100) == 0) ++ audio_n = (128 * hparms->sample_rate) / 900; ++ else ++ audio_n = (128 * hparms->sample_rate) / 1000; ++ ++ if (hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_EAC3 || ++ hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_DTS_HD) ++ audio_n *= 4; ++ ++ return audio_n; ++} ++ ++static u8 meson_txc_hdmi_hdmi_codec_coding_type(struct hdmi_codec_params *hparms) ++{ ++ switch (hparms->cea.coding_type) { ++ case HDMI_AUDIO_CODING_TYPE_MLP: ++ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_HBR_AUDIO_PACKET; ++ case HDMI_AUDIO_CODING_TYPE_DSD: ++ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_ONE_BIT_AUDIO; ++ case HDMI_AUDIO_CODING_TYPE_DST: ++ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_DST_AUDIO_PACKET; ++ default: ++ return TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_AUDIO_SAMPLE_PACKET; ++ } ++} ++ ++static int meson_txc_hdmi_audio_prepare(struct drm_connector *connector, ++ struct drm_bridge *bridge, ++ struct hdmi_codec_daifmt *fmt, ++ struct hdmi_codec_params *hparms) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ u16 audio_n, audio_tx_format; ++ unsigned int i; ++ ++ if (hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_MLP) { ++ /* ++ * TODO: fixed CTS is not supported yet, it needs special ++ * TX_SYS1_ACR_N_* settings ++ */ ++ return -EINVAL; ++ } ++ ++ switch (hparms->sample_width) { ++ case 16: ++ audio_tx_format = FIELD_PREP(TX_AUDIO_FORMAT_BIT_WIDTH_MASK, ++ TX_AUDIO_FORMAT_BIT_WIDTH_16); ++ break; ++ ++ case 20: ++ audio_tx_format = FIELD_PREP(TX_AUDIO_FORMAT_BIT_WIDTH_MASK, ++ TX_AUDIO_FORMAT_BIT_WIDTH_20); ++ break; ++ ++ case 24: ++ audio_tx_format = FIELD_PREP(TX_AUDIO_FORMAT_BIT_WIDTH_MASK, ++ TX_AUDIO_FORMAT_BIT_WIDTH_24); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ switch (fmt->fmt) { ++ case HDMI_I2S: ++ regmap_set_bits(priv->regmap, HDMI_OTHER_CTRL1, ++ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON); ++ ++ audio_tx_format |= TX_AUDIO_FORMAT_SPDIF_OR_I2S | ++ TX_AUDIO_FORMAT_I2S_ONE_BIT_OR_I2S | ++ FIELD_PREP(TX_AUDIO_FORMAT_I2S_FORMAT, 0x2); ++ ++ if (hparms->channels > 2) ++ audio_tx_format |= TX_AUDIO_FORMAT_I2S_2_OR_8_CH; ++ ++ regmap_write(priv->regmap, TX_AUDIO_FORMAT, audio_tx_format); ++ ++ regmap_write(priv->regmap, TX_AUDIO_I2S, TX_AUDIO_I2S_ENABLE); ++ regmap_write(priv->regmap, TX_AUDIO_SPDIF, 0x0); ++ break; ++ ++ case HDMI_SPDIF: ++ regmap_clear_bits(priv->regmap, HDMI_OTHER_CTRL1, ++ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON); ++ ++ if (hparms->cea.coding_type == HDMI_AUDIO_CODING_TYPE_STREAM) ++ audio_tx_format |= TX_AUDIO_FORMAT_SPDIF_CHANNEL_STATUS_FROM_DATA_OR_REG; ++ ++ regmap_write(priv->regmap, TX_AUDIO_FORMAT, audio_tx_format); ++ ++ regmap_write(priv->regmap, TX_AUDIO_I2S, 0x0); ++ regmap_write(priv->regmap, TX_AUDIO_SPDIF, TX_AUDIO_SPDIF_ENABLE); ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ if (hparms->channels > 2) ++ regmap_write(priv->regmap, TX_AUDIO_HEADER, ++ TX_AUDIO_HEADER_AUDIO_SAMPLE_PACKET_HEADER_LAYOUT1); ++ else ++ regmap_write(priv->regmap, TX_AUDIO_HEADER, 0x0); ++ ++ regmap_write(priv->regmap, TX_AUDIO_SAMPLE, ++ FIELD_PREP(TX_AUDIO_SAMPLE_CHANNEL_VALID, ++ BIT(hparms->channels) - 1)); ++ ++ audio_n = meson_txc_hdmi_hdmi_codec_calc_audio_n(hparms); ++ ++ regmap_write(priv->regmap, TX_SYS1_ACR_N_0, ++ FIELD_PREP(TX_SYS1_ACR_N_0_N_BYTE0, ++ (audio_n >> 0) & 0xff)); ++ regmap_write(priv->regmap, TX_SYS1_ACR_N_1, ++ FIELD_PREP(TX_SYS1_ACR_N_1_N_BYTE1, ++ (audio_n >> 8) & 0xff)); ++ regmap_update_bits(priv->regmap, TX_SYS1_ACR_N_2, ++ TX_SYS1_ACR_N_2_N_UPPER_NIBBLE, ++ FIELD_PREP(TX_SYS1_ACR_N_2_N_UPPER_NIBBLE, ++ (audio_n >> 16) & 0xf)); ++ ++ regmap_write(priv->regmap, TX_SYS0_ACR_CTS_0, 0x0); ++ regmap_write(priv->regmap, TX_SYS0_ACR_CTS_1, 0x0); ++ regmap_write(priv->regmap, TX_SYS0_ACR_CTS_2, ++ TX_SYS0_ACR_CTS_2_FORCE_ARC_STABLE); ++ ++ regmap_write(priv->regmap, TX_AUDIO_CONTROL, ++ TX_AUDIO_CONTROL_AUTO_AUDIO_FIFO_CLEAR | ++ FIELD_PREP(TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_MASK, ++ meson_txc_hdmi_hdmi_codec_coding_type(hparms)) | ++ TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_FLAT); ++ ++ for (i = 0; i < ARRAY_SIZE(hparms->iec.status); i++) { ++ unsigned char sub1, sub2; ++ ++ sub1 = sub2 = hparms->iec.status[i]; ++ ++ if (i == 2) { ++ sub1 |= FIELD_PREP(IEC958_AES2_CON_CHANNEL, 1); ++ sub2 |= FIELD_PREP(IEC958_AES2_CON_CHANNEL, 2); ++ } ++ ++ regmap_write(priv->regmap, TX_IEC60958_SUB1_OFFSET + i, sub1); ++ regmap_write(priv->regmap, TX_IEC60958_SUB2_OFFSET + i, sub2); ++ } ++ ++ return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, ++ &hparms->cea); ++} ++ ++static int meson_txc_hdmi_audio_mute_stream(struct drm_connector *connector, ++ struct drm_bridge *bridge, ++ bool enable, int direction) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ ++ regmap_write(priv->regmap, TX_AUDIO_PACK, ++ enable ? 0 : TX_AUDIO_PACK_AUDIO_SAMPLE_PACKETS_ENABLE); ++ ++ return 0; ++} ++ ++static int meson_txc_hdmi_audio_startup(struct drm_connector *connector, ++ struct drm_bridge *bridge) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ ++ regmap_clear_bits(priv->regmap, TX_PACKET_CONTROL_2, ++ TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE); ++ ++ /* reset audio master and sample */ ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, ++ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN | ++ TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN); ++ regmap_write(priv->regmap, TX_SYS5_TX_SOFT_RESET_1, 0x0); ++ ++ regmap_write(priv->regmap, TX_AUDIO_CONTROL_MORE, ++ TX_AUDIO_CONTROL_MORE_ENABLE); ++ ++ regmap_write(priv->regmap, TX_AUDIO_FIFO, ++ FIELD_PREP(TX_AUDIO_FIFO_FIFO_DEPTH_MASK, ++ TX_AUDIO_FIFO_FIFO_DEPTH_512) | ++ FIELD_PREP(TX_AUDIO_FIFO_CRITICAL_THRESHOLD_MASK, ++ TX_AUDIO_FIFO_CRITICAL_THRESHOLD_DEPTH_DIV16) | ++ FIELD_PREP(TX_AUDIO_FIFO_NORMAL_THRESHOLD_MASK, ++ TX_AUDIO_FIFO_NORMAL_THRESHOLD_DEPTH_DIV8)); ++ ++ regmap_write(priv->regmap, TX_AUDIO_LIPSYNC, 0x0); ++ ++ regmap_write(priv->regmap, TX_SYS1_ACR_N_2, ++ FIELD_PREP(TX_SYS1_ACR_N_2_N_MEAS_TOLERANCE, 0x3)); ++ ++ return 0; ++} ++ ++static void meson_txc_hdmi_audio_shutdown(struct drm_connector *connector, ++ struct drm_bridge *bridge) ++{ ++ struct meson_txc_hdmi *priv = bridge_to_meson_txc_hdmi(bridge); ++ ++ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector); ++ ++ regmap_write(priv->regmap, TX_AUDIO_CONTROL_MORE, 0x0); ++ regmap_clear_bits(priv->regmap, HDMI_OTHER_CTRL1, ++ HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON); ++ ++ regmap_set_bits(priv->regmap, TX_PACKET_CONTROL_2, ++ TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE); ++} ++ ++static const struct drm_bridge_funcs meson_txc_hdmi_bridge_funcs = { ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_reset = drm_atomic_helper_bridge_reset, ++ .attach = meson_txc_hdmi_bridge_attach, ++ .atomic_get_output_bus_fmts = meson_txc_hdmi_bridge_atomic_get_output_bus_fmts, ++ .atomic_get_input_bus_fmts = meson_txc_hdmi_bridge_atomic_get_input_bus_fmts, ++ .atomic_enable = meson_txc_hdmi_bridge_atomic_enable, ++ .atomic_disable = meson_txc_hdmi_bridge_atomic_disable, ++ .mode_valid = meson_txc_hdmi_bridge_mode_valid, ++ .detect = meson_txc_hdmi_bridge_detect, ++ .edid_read = meson_txc_hdmi_bridge_edid_read, ++ .hdmi_tmds_char_rate_valid = meson_txc_hdmi_tmds_char_rate_valid, ++ .hdmi_write_infoframe = meson_txc_hdmi_write_infoframe, ++ .hdmi_clear_infoframe = meson_txc_hdmi_clear_infoframe, ++ .hdmi_audio_prepare = meson_txc_hdmi_audio_prepare, ++ .hdmi_audio_mute_stream = meson_txc_hdmi_audio_mute_stream, ++ .hdmi_audio_startup = meson_txc_hdmi_audio_startup, ++ .hdmi_audio_shutdown = meson_txc_hdmi_audio_shutdown, ++}; ++ ++static int meson_txc_hdmi_hw_init(struct meson_txc_hdmi *priv, ++ struct device *dev) ++{ ++ unsigned long ddc_i2c_bus_clk_hz = 500 * 1000; ++ unsigned long sys_clk_hz = 24 * 1000 * 1000; ++ int ret; ++ ++ ret = phy_init(priv->phy); ++ if (ret) { ++ dev_err(dev, "Failed to initialize the PHY: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_set_rate(priv->sys_clk, sys_clk_hz); ++ if (ret) { ++ dev_err(dev, "Failed to set HDMI system clock to 24MHz\n"); ++ goto err_phy_exit; ++ } ++ ++ ret = clk_prepare_enable(priv->sys_clk); ++ if (ret) { ++ dev_err(dev, "Failed to enable the sys clk: %d\n", ret); ++ goto err_phy_exit; ++ } ++ ++ regmap_set_bits(priv->regmap, HDMI_OTHER_CTRL1, ++ HDMI_OTHER_CTRL1_POWER_ON); ++ ++ regmap_write(priv->regmap, TX_HDMI_PHY_CONFIG0, ++ TX_HDMI_PHY_CONFIG0_HDMI_COMMON_B7_B0); ++ ++ regmap_write(priv->regmap, TX_HDCP_MODE, TX_HDCP_MODE_ESS_CONFIG); ++ ++ /* ++ * The vendor driver comments that this is a setting for "Band-gap and ++ * main-bias". 0x1d = power-up, 0x00 = power-down. ++ */ ++ regmap_write(priv->regmap, TX_SYS1_AFE_TEST, 0x1d); ++ ++ meson_txc_hdmi_set_serializer_clock(priv, HDMI_COLORIMETRY_NONE, 0, 8); ++ ++ /* ++ * The vendor driver has a comment with the following information for ++ * the magic value: ++ * bit[2:0]=011: CK channel output TMDS CLOCK ++ * bit[2:0]=101, ck channel output PHYCLCK ++ */ ++ regmap_write(priv->regmap, TX_SYS1_AFE_CONNECT, 0xfb); ++ ++ /* Termination resistor calib value */ ++ regmap_write(priv->regmap, TX_CORE_CALIB_VALUE, 0x0f); ++ ++ /* HPD glitch filter */ ++ regmap_write(priv->regmap, TX_HDCP_HPD_FILTER_L, 0xa0); ++ regmap_write(priv->regmap, TX_HDCP_HPD_FILTER_H, 0xa0); ++ ++ /* Disable MEM power-down */ ++ regmap_write(priv->regmap, TX_MEM_PD_REG0, 0x0); ++ ++ regmap_write(priv->regmap, TX_HDCP_CONFIG3, ++ FIELD_PREP(TX_HDCP_CONFIG3_DDC_I2C_BUS_CLOCK_TIME_DIVIDER, ++ (sys_clk_hz / ddc_i2c_bus_clk_hz) - 1)); ++ ++ /* Enable software controlled DDC transaction */ ++ regmap_write(priv->regmap, TX_HDCP_EDID_CONFIG, ++ TX_HDCP_EDID_CONFIG_FORCED_MEM_COPY_DONE | ++ TX_HDCP_EDID_CONFIG_MEM_COPY_DONE_CONFIG); ++ regmap_write(priv->regmap, TX_CORE_EDID_CONFIG_MORE, ++ TX_CORE_EDID_CONFIG_MORE_SYS_TRIGGER_CONFIG_SEMI_MANU); ++ ++ /* mask (= disable) all interrupts */ ++ regmap_write(priv->regmap, HDMI_OTHER_INTR_MASKN, ++ HDMI_OTHER_INTR_MASKN_TX_EDID_INT_RISE | ++ HDMI_OTHER_INTR_MASKN_TX_HPD_INT_FALL | ++ HDMI_OTHER_INTR_MASKN_TX_HPD_INT_RISE); ++ ++ /* clear any pending interrupt */ ++ regmap_write(priv->regmap, HDMI_OTHER_INTR_STAT_CLR, ++ HDMI_OTHER_INTR_STAT_CLR_EDID_RISING | ++ HDMI_OTHER_INTR_STAT_CLR_HPD_FALLING | ++ HDMI_OTHER_INTR_STAT_CLR_HPD_RISING); ++ ++ return 0; ++ ++err_phy_exit: ++ phy_exit(priv->phy); ++ return ret; ++} ++ ++static void meson_txc_hdmi_hw_exit(struct meson_txc_hdmi *priv, ++ struct device *dev) ++{ ++ int ret; ++ ++ /* mask (= disable) all interrupts */ ++ regmap_write(priv->regmap, HDMI_OTHER_INTR_MASKN, ++ HDMI_OTHER_INTR_MASKN_TX_EDID_INT_RISE | ++ HDMI_OTHER_INTR_MASKN_TX_HPD_INT_FALL | ++ HDMI_OTHER_INTR_MASKN_TX_HPD_INT_RISE); ++ ++ regmap_clear_bits(priv->regmap, HDMI_OTHER_CTRL1, ++ HDMI_OTHER_CTRL1_POWER_ON); ++ ++ clk_disable_unprepare(priv->sys_clk); ++ ++ ret = phy_exit(priv->phy); ++ if (ret) ++ dev_err(dev, "Failed to exit the PHY: %d\n", ret); ++} ++ ++static int meson_txc_hdmi_probe(struct platform_device *pdev) ++{ ++ struct device_node *endpoint, *remote; ++ struct device *dev = &pdev->dev; ++ struct meson_txc_hdmi *priv; ++ void __iomem *base; ++ struct clk *pclk; ++ u32 regval; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ priv->regmap = devm_regmap_init(dev, NULL, base, ++ &meson_txc_hdmi_regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ priv->sys_clk = devm_clk_get(dev, "sys"); ++ if (IS_ERR(priv->sys_clk)) ++ return dev_err_probe(dev, PTR_ERR(priv->sys_clk), ++ "Failed to get the sys clock\n"); ++ ++ priv->phy = devm_phy_get(dev, "hdmi"); ++ if (IS_ERR(priv->phy)) ++ return dev_err_probe(dev, PTR_ERR(priv->phy), ++ "Failed to get the HDMI PHY\n"); ++ ++ endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); ++ if (!endpoint) ++ return dev_err_probe(dev, -ENODEV, ++ "Missing endpoint in port@1\n"); ++ ++ remote = of_graph_get_remote_port_parent(endpoint); ++ of_node_put(endpoint); ++ if (!remote) ++ return dev_err_probe(dev, -ENODEV, ++ "Endpoint in port@1 unconnected\n"); ++ ++ if (!of_device_is_available(remote)) { ++ of_node_put(remote); ++ return dev_err_probe(dev, -ENODEV, ++ "port@1 remote device is disabled\n"); ++ } ++ ++ pclk = devm_clk_get_enabled(dev, "pclk"); ++ if (IS_ERR(pclk)) ++ return dev_err_probe(dev, PTR_ERR(pclk), ++ "Failed to get and enable the pclk\n"); ++ ++ priv->next_bridge = of_drm_find_bridge(remote); ++ of_node_put(remote); ++ if (!priv->next_bridge) ++ return -EPROBE_DEFER; ++ ++ regval = readl(base + HDMI_CTRL_PORT); ++ regval |= HDMI_CTRL_PORT_APB3_ERR_EN; ++ writel(regval, base + HDMI_CTRL_PORT); ++ ++ ret = meson_txc_hdmi_hw_init(priv, dev); ++ if (ret) ++ return ret; ++ ++ priv->bridge.of_node = dev->of_node; ++ priv->bridge.driver_private = priv; ++ priv->bridge.funcs = &meson_txc_hdmi_bridge_funcs; ++ priv->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | ++ DRM_BRIDGE_OP_HDMI; ++ priv->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ++ priv->bridge.interlace_allowed = true; ++ priv->bridge.max_bpc = 12; ++ priv->bridge.supported_formats = BIT(HDMI_COLORSPACE_RGB) | ++ BIT(HDMI_COLORSPACE_YUV422) | ++ BIT(HDMI_COLORSPACE_YUV444); ++ priv->bridge.vendor = "Amlogic"; ++ priv->bridge.product = "TranSwitch-HDMI"; ++ priv->bridge.hdmi_audio_dev = dev; ++ priv->bridge.hdmi_audio_max_i2s_playback_channels = 8; ++ priv->bridge.hdmi_audio_spdif_playback = 1; ++ priv->bridge.hdmi_audio_dai_port = 2; ++ ++ drm_bridge_add(&priv->bridge); ++ ++ return 0; ++} ++ ++static void meson_txc_hdmi_remove(struct platform_device *pdev) ++{ ++ struct meson_txc_hdmi *priv = platform_get_drvdata(pdev); ++ ++ drm_bridge_remove(&priv->bridge); ++ ++ meson_txc_hdmi_hw_exit(priv, &pdev->dev); ++} ++ ++static const struct of_device_id meson_txc_hdmi_of_table[] = { ++ { .compatible = "amlogic,meson8-hdmi-tx" }, ++ { .compatible = "amlogic,meson8b-hdmi-tx" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, meson_txc_hdmi_of_table); ++ ++static struct platform_driver meson_txc_hdmi_platform_driver = { ++ .probe = meson_txc_hdmi_probe, ++ .remove = meson_txc_hdmi_remove, ++ .driver = { ++ .name = "meson-transwitch-hdmi", ++ .of_match_table = meson_txc_hdmi_of_table, ++ }, ++}; ++module_platform_driver(meson_txc_hdmi_platform_driver); ++ ++MODULE_AUTHOR("Martin Blumenstingl "); ++MODULE_DESCRIPTION("Amlogic Meson8 and Meson8b TranSwitch HDMI 1.4 TX driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/meson/meson_transwitch_hdmi.h b/drivers/gpu/drm/meson/meson_transwitch_hdmi.h +new file mode 100644 +index 000000000..a1dd7c0a9 +--- /dev/null ++++ b/drivers/gpu/drm/meson/meson_transwitch_hdmi.h +@@ -0,0 +1,543 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2021 Martin Blumenstingl ++ * ++ * All registers and magic values are taken from Amlogic's GPL kernel sources: ++ * Copyright (C) 2010 Amlogic, Inc. ++ */ ++ ++#include ++#include ++ ++#ifndef __MESON_TRANSWITCH_HDMI_H__ ++#define __MESON_TRANSWITCH_HDMI_H__ ++ ++/* HDMI TX register */ ++ ++// System config 0 ++#define TX_SYS0_AFE_SIGNAL 0x0000 ++#define TX_SYS0_AFE_LOOP 0x0001 ++#define TX_SYS0_ACR_CTS_0 0x0002 ++ #define TX_SYS0_ACR_CTS_0_AUDIO_CTS_BYTE0 GENMASK(7, 0) ++#define TX_SYS0_ACR_CTS_1 0x0003 ++ #define TX_SYS0_ACR_CTS_1_AUDIO_CTS_BYTE1 GENMASK(7, 0) ++#define TX_SYS0_ACR_CTS_2 0x0004 ++ #define TX_SYS0_ACR_CTS_2_FORCE_ARC_STABLE BIT(5) ++#define TX_SYS0_BIST_CONTROL 0x0005 ++ #define TX_SYS0_BIST_CONTROL_AFE_BIST_ENABLE BIT(7) ++ #define TX_SYS0_BIST_CONTROL_TMDS_SHIFT_PATTERN_SELECT BIT(6) ++ #define TX_SYS0_BIST_CONTROL_TMDS_PRBS_PATTERN_SELECT GENMASK(5, 4) ++ #define TX_SYS0_BIST_CONTROL_TMDS_REPEAT_BIST_PATTERN GENMASK(2, 0) ++ ++#define TX_SYS0_BIST_DATA_0 0x0006 ++#define TX_SYS0_BIST_DATA_1 0x0007 ++#define TX_SYS0_BIST_DATA_2 0x0008 ++#define TX_SYS0_BIST_DATA_3 0x0009 ++#define TX_SYS0_BIST_DATA_4 0x000A ++#define TX_SYS0_BIST_DATA_5 0x000B ++#define TX_SYS0_BIST_DATA_6 0x000C ++#define TX_SYS0_BIST_DATA_7 0x000D ++#define TX_SYS0_BIST_DATA_8 0x000E ++#define TX_SYS0_BIST_DATA_9 0x000F ++ ++// system config 1 ++#define TX_HDMI_PHY_CONFIG0 0x0010 ++ #define TX_HDMI_PHY_CONFIG0_HDMI_COMMON_B7_B0 GENMASK(7, 0) ++#define TX_HDMI_PHY_CONFIG1 0x0010 ++ #define TX_HDMI_PHY_CONFIG1_HDMI_COMMON_B11_B8 GENMASK(3, 0) ++ #define TX_HDMI_PHY_CONFIG1_HDMI_CTL_REG_B3_B0 GENMASK(7, 4) ++#define TX_HDMI_PHY_CONFIG2 0x0012 ++ #define TX_HDMI_PHY_CONFIG_HDMI_CTL_REG_B11_B4 GENMASK(7, 0) ++#define TX_HDMI_PHY_CONFIG3 0x0013 ++ #define TX_HDMI_PHY_CONFIG3_HDMI_L2H_CTL GENMASK(3, 0) ++ #define TX_HDMI_PHY_CONFIG3_HDMI_MDR_PU GENMASK(7, 4) ++#define TX_HDMI_PHY_CONFIG4 0x0014 ++ #define TX_HDMI_PHY_CONFIG4_HDMI_LF_PD BIT(0) ++ #define TX_HDMI_PHY_CONFIG4_HDMI_PHY_CLK_EN BIT(1) ++ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE GENMASK(3, 2) ++ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_NORMAL 0x0 ++ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_CLK_CH3_EQUAL_CH0 0x1 ++ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_ALTERNATE_HIGH_LOW 0x2 ++ #define TX_HDMI_PHY_CONFIG4_HDMI_MODE_ALTERNATE_LOW_HIGH 0x3 ++ #define TX_HDMI_PHY_CONFIG4_HDMI_PREM_CTL GENMASK(7, 4) ++#define TX_HDMI_PHY_CONFIG5 0x0015 ++ #define TX_HDMI_PHY_CONFIG5_HDMI_VCM_CTL GENMASK(7, 5) ++ #define TX_HDMI_PHY_CONFIG5_HDMI_PREFCTL GENMASK(2, 0) ++#define TX_HDMI_PHY_CONFIG6 0x0016 ++ #define TX_HDMI_PHY_CONFIG6_HDMI_RTERM_CTL GENMASK(3, 0) ++ #define TX_HDMI_PHY_CONFIG6_HDMI_SWING_CTL GENMASK(7, 4) ++#define TX_SYS1_AFE_TEST 0x0017 ++#define TX_SYS1_PLL 0x0018 ++#define TX_SYS1_TUNE 0x0019 ++#define TX_SYS1_AFE_CONNECT 0x001A ++ ++#define TX_SYS1_ACR_N_0 0x001C ++ #define TX_SYS1_ACR_N_0_N_BYTE0 GENMASK(7, 0) ++#define TX_SYS1_ACR_N_1 0x001D ++ #define TX_SYS1_ACR_N_1_N_BYTE1 GENMASK(7, 0) ++#define TX_SYS1_ACR_N_2 0x001E ++ #define TX_SYS1_ACR_N_2_N_MEAS_TOLERANCE GENMASK(7, 4) ++ #define TX_SYS1_ACR_N_2_N_UPPER_NIBBLE GENMASK(3, 0) ++#define TX_SYS1_PRBS_DATA 0x001F ++ #define TX_SYS1_PRBS_DATA_PRBS_MODE GENMASK(1, 0) ++ #define TX_SYS1_PRBS_DATA_PRBS_MODE_11 0x0 ++ #define TX_SYS1_PRBS_DATA_PRBS_MODE_15 0x1 ++ #define TX_SYS1_PRBS_DATA_PRBS_MODE_7 0x2 ++ #define TX_SYS1_PRBS_DATA_PRBS_MODE_31 0x3 ++ ++// HDCP CONFIG ++#define TX_HDCP_ECC_CONFIG 0x0024 ++#define TX_HDCP_CRC_CONFIG 0x0025 ++#define TX_HDCP_EDID_CONFIG 0x0026 ++ #define TX_HDCP_EDID_CONFIG_FORCED_SYS_TRIGGER BIT(7) ++ #define TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG BIT(6) ++ #define TX_HDCP_EDID_CONFIG_MEM_ACC_SEQ_MODE BIT(5) ++ #define TX_HDCP_EDID_CONFIG_MEM_ACC_SEQ_START BIT(4) ++ #define TX_HDCP_EDID_CONFIG_FORCED_MEM_COPY_DONE BIT(3) ++ #define TX_HDCP_EDID_CONFIG_MEM_COPY_DONE_CONFIG BIT(2) ++ #define TX_HDCP_EDID_CONFIG_SYS_TRIGGER_CONFIG_SEMI_MANU BIT(1) ++ ++#define TX_HDCP_MEM_CONFIG 0x0027 ++ #define TX_HDCP_MEM_CONFIG_READ_DECRYPT BIT(3) ++ ++#define TX_HDCP_HPD_FILTER_L 0x0028 ++#define TX_HDCP_HPD_FILTER_H 0x0029 ++#define TX_HDCP_ENCRYPT_BYTE 0x002A ++#define TX_HDCP_CONFIG0 0x002B ++ #define TX_HDCP_CONFIG0_ROM_ENCRYPT_OFF GENMASK(4, 3) ++ ++#define TX_HDCP_CONFIG1 0x002C ++#define TX_HDCP_CONFIG2 0x002D ++#define TX_HDCP_CONFIG3 0x002E ++ #define TX_HDCP_CONFIG3_DDC_I2C_BUS_CLOCK_TIME_DIVIDER GENMASK(7, 0) ++ ++#define TX_HDCP_MODE 0x002F ++ #define TX_HDCP_MODE_CP_DESIRED BIT(7) ++ #define TX_HDCP_MODE_ESS_CONFIG BIT(6) ++ #define TX_HDCP_MODE_SET_AVMUTE BIT(5) ++ #define TX_HDCP_MODE_CLEAR_AVMUTE BIT(4) ++ #define TX_HDCP_MODE_HDCP_1_1 BIT(3) ++ #define TX_HDCP_MODE_VSYNC_HSYNC_FORCED_POLARITY_SELECT BIT(2) ++ #define TX_HDCP_MODE_FORCED_VSYNC_POLARITY BIT(1) ++ #define TX_HDCP_MODE_FORCED_HSYNC_POLARITY BIT(0) ++ ++// Video config, part 1 ++#define TX_VIDEO_ACTIVE_PIXELS_0 0x0030 ++#define TX_VIDEO_ACTIVE_PIXELS_1 0x0031 ++#define TX_VIDEO_FRONT_PIXELS 0x0032 ++#define TX_VIDEO_HSYNC_PIXELS 0x0033 ++#define TX_VIDEO_BACK_PIXELS 0x0034 ++#define TX_VIDEO_ACTIVE_LINES_0 0x0035 ++#define TX_VIDEO_ACTIVE_LINES_1 0x0036 ++#define TX_VIDEO_EOF_LINES 0x0037 ++#define TX_VIDEO_VSYNC_LINES 0x0038 ++#define TX_VIDEO_SOF_LINES 0x0039 ++#define TX_VIDEO_DTV_TIMING 0x003A ++ #define TX_VIDEO_DTV_TIMING_FORCE_DTV_TIMING_AUTO BIT(7) ++ #define TX_VIDEO_DTV_TIMING_FORCE_VIDEO_SCAN BIT(6) ++ #define TX_VIDEO_DTV_TIMING_FORCE_VIDEO_FIELD BIT(5) ++ #define TX_VIDEO_DTV_TIMING_DISABLE_VIC39_CORRECTION BIT(4) ++ ++#define TX_VIDEO_DTV_MODE 0x003B ++ #define TX_VIDEO_DTV_MODE_FORCED_DEFAULT_PHASE BIT(7) ++ #define TX_VIDEO_DTV_MODE_COLOR_DEPTH GENMASK(1, 0) ++ ++#define TX_VIDEO_DTV_FORMAT0 0x003C ++#define TX_VIDEO_DTV_FORMAT1 0x003D ++#define TX_VIDEO_PIXEL_PACK 0x003F ++// video config, part 2 ++#define TX_VIDEO_CSC_COEFF_B0 0x0040 ++#define TX_VIDEO_CSC_COEFF_B1 0x0041 ++#define TX_VIDEO_CSC_COEFF_R0 0x0042 ++#define TX_VIDEO_CSC_COEFF_R1 0x0043 ++#define TX_VIDEO_CSC_COEFF_CB0 0x0044 ++#define TX_VIDEO_CSC_COEFF_CB1 0x0045 ++#define TX_VIDEO_CSC_COEFF_CR0 0x0046 ++#define TX_VIDEO_CSC_COEFF_CR1 0x0047 ++#define TX_VIDEO_DTV_OPTION_L 0x0048 ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_RGB444 0x0 ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_YCBCR444 0x1 ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_FORMAT_YCBCR422 0x3 ++ #define TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_FORMAT GENMASK(7, 6) ++ #define TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_FORMAT GENMASK(5, 4) ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_24_BIT 0x0 ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_30_BIT 0x1 ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_36_BIT 0x2 ++ #define TX_VIDEO_DTV_OPTION_L_COLOR_DEPTH_48_BIT 0x3 ++ #define TX_VIDEO_DTV_OPTION_L_OUTPUT_COLOR_DEPTH GENMASK(3, 2) ++ #define TX_VIDEO_DTV_OPTION_L_INPUT_COLOR_DEPTH GENMASK(1, 0) ++ ++#define TX_VIDEO_DTV_OPTION_H 0x0049 ++ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_235 0x0 ++ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_16_240 0x1 ++ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_1_254 0x2 ++ #define TX_VIDEO_DTV_OPTION_H_COLOR_RANGE_0_255 0x3 ++ #define TX_VIDEO_DTV_OPTION_H_OUTPUT_COLOR_RANGE GENMASK(3, 2) ++ #define TX_VIDEO_DTV_OPTION_H_INPUT_COLOR_RANGE GENMASK(1, 0) ++ ++#define TX_VIDEO_DTV_FILTER 0x004A ++#define TX_VIDEO_DTV_DITHER 0x004B ++#define TX_VIDEO_DTV_DEDITHER 0x004C ++#define TX_VIDEO_PROC_CONFIG0 0x004E ++#define TX_VIDEO_PROC_CONFIG1 0x004F ++ ++// Audio config ++#define TX_AUDIO_FORMAT 0x0058 ++ #define TX_AUDIO_FORMAT_SPDIF_OR_I2S BIT(7) ++ #define TX_AUDIO_FORMAT_I2S_2_OR_8_CH BIT(6) ++ #define TX_AUDIO_FORMAT_I2S_FORMAT GENMASK(5, 4) ++ #define TX_AUDIO_FORMAT_BIT_WIDTH_MASK GENMASK(3, 2) ++ #define TX_AUDIO_FORMAT_BIT_WIDTH_16 0x1 ++ #define TX_AUDIO_FORMAT_BIT_WIDTH_20 0x2 ++ #define TX_AUDIO_FORMAT_BIT_WIDTH_24 0x3 ++ #define TX_AUDIO_FORMAT_WS_POLARITY BIT(1) ++ #define TX_AUDIO_FORMAT_I2S_ONE_BIT_OR_I2S BIT(0) ++ #define TX_AUDIO_FORMAT_SPDIF_CHANNEL_STATUS_FROM_DATA_OR_REG BIT(0) ++ ++#define TX_AUDIO_SPDIF 0x0059 ++ #define TX_AUDIO_SPDIF_ENABLE BIT(0) ++#define TX_AUDIO_I2S 0x005A ++ #define TX_AUDIO_I2S_ENABLE BIT(0) ++#define TX_AUDIO_FIFO 0x005B ++ #define TX_AUDIO_FIFO_FIFO_DEPTH_MASK GENMASK(7, 4) ++ #define TX_AUDIO_FIFO_FIFO_DEPTH_512 0x4 ++ #define TX_AUDIO_FIFO_CRITICAL_THRESHOLD_MASK GENMASK(3, 2) ++ #define TX_AUDIO_FIFO_CRITICAL_THRESHOLD_DEPTH_DIV16 0x2 ++ #define TX_AUDIO_FIFO_NORMAL_THRESHOLD_MASK GENMASK(1, 0) ++ #define TX_AUDIO_FIFO_NORMAL_THRESHOLD_DEPTH_DIV8 0x1 ++#define TX_AUDIO_LIPSYNC 0x005C ++ #define TX_AUDIO_LIPSYNC_NORMALIZED_LIPSYNC_PARAM GENMASK(7, 0) ++#define TX_AUDIO_CONTROL 0x005D ++ #define TX_AUDIO_CONTROL_FORCED_AUDIO_FIFO_CLEAR BIT(7) ++ #define TX_AUDIO_CONTROL_AUTO_AUDIO_FIFO_CLEAR BIT(6) ++ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_MASK GENMASK(5, 4) ++ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_AUDIO_SAMPLE_PACKET 0x0 ++ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_ONE_BIT_AUDIO 0x1 ++ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_HBR_AUDIO_PACKET 0x2 ++ #define TX_AUDIO_CONTROL_AUDIO_PACKET_TYPE_DST_AUDIO_PACKET 0x3 ++ #define TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_VALID BIT(2) ++ #define TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_USER BIT(1) ++ #define TX_AUDIO_CONTROL_AUDIO_SAMPLE_PACKET_FLAT BIT(0) ++#define TX_AUDIO_HEADER 0x005E ++ #define TX_AUDIO_HEADER_AUDIO_SAMPLE_PACKET_HEADER_LAYOUT1 BIT(7) ++ #define TX_AUDIO_HEADER_SET_NORMAL_DOUBLE_IN_DST_PACKET_HEADER BIT(6) ++#define TX_AUDIO_SAMPLE 0x005F ++ #define TX_AUDIO_SAMPLE_CHANNEL_VALID GENMASK(7, 0) ++#define TX_AUDIO_VALID 0x0060 ++#define TX_AUDIO_USER 0x0061 ++#define TX_AUDIO_PACK 0x0062 ++ #define TX_AUDIO_PACK_AUDIO_SAMPLE_PACKETS_ENABLE BIT(0) ++#define TX_AUDIO_CONTROL_MORE 0x0064 ++ #define TX_AUDIO_CONTROL_MORE_ENABLE BIT(0) ++ ++// tmds config ++#define TX_TMDS_MODE 0x0068 ++ #define TX_TMDS_MODE_FORCED_HDMI BIT(7) ++ #define TX_TMDS_MODE_HDMI_CONFIG BIT(6) ++ #define TX_TMDS_MODE_BIT_SWAP BIT(3) ++ #define TX_TMDS_MODE_CHANNEL_SWAP GENMASK(2, 0) ++ ++#define TX_TMDS_CONFIG0 0x006C ++#define TX_TMDS_CONFIG1 0x006D ++ ++// packet config ++#define TX_PACKET_ALLOC_ACTIVE_1 0x0078 ++#define TX_PACKET_ALLOC_ACTIVE_2 0x0079 ++#define TX_PACKET_ALLOC_EOF_1 0x007A ++#define TX_PACKET_ALLOC_EOF_2 0x007B ++#define TX_PACKET_ALLOC_SOF_1 0x007C ++#define TX_PACKET_ALLOC_SOF_2 0x007D ++#define TX_PACKET_CONTROL_1 0x007E ++ #define TX_PACKET_CONTROL_1_FORCE_PACKET_TIMING BIT(7) ++ #define TX_PACKET_CONTROL_1_PACKET_ALLOC_MODE BIT(6) ++ #define TX_PACKET_CONTROL_1_PACKET_START_LATENCY GENMASK(5, 0) ++ ++#define TX_PACKET_CONTROL_2 0x007F ++ #define TX_PACKET_CONTROL_2_AUDIO_REQUEST_DISABLE BIT(3) ++ #define TX_PACKET_CONTROL_2_HORIZONTAL_GC_PACKET_TRANSPORT_EN BIT(1) ++ ++#define TX_CORE_EDID_CONFIG_MORE 0x0080 ++ #define TX_CORE_EDID_CONFIG_MORE_KEEP_EDID_ERROR BIT(1) ++ #define TX_CORE_EDID_CONFIG_MORE_SYS_TRIGGER_CONFIG_SEMI_MANU BIT(0) ++ ++#define TX_CORE_ALLOC_VSYNC_0 0x0081 ++#define TX_CORE_ALLOC_VSYNC_1 0x0082 ++#define TX_CORE_ALLOC_VSYNC_2 0x0083 ++#define TX_MEM_PD_REG0 0x0084 ++ ++// core config ++#define TX_CORE_DATA_CAPTURE_1 0x00F0 ++#define TX_CORE_DATA_CAPTURE_2 0x00F1 ++ #define TX_CORE_DATA_CAPTURE_2_AUDIO_SOURCE_SELECT GENMASK(7, 6) ++ #define TX_CORE_DATA_CAPTURE_2_EXTERNAL_PACKET_ENABLE BIT(5) ++ #define TX_CORE_DATA_CAPTURE_2_INTERNAL_PACKET_ENABLE BIT(4) ++ #define TX_CORE_DATA_CAPTURE_2_AFE_FIFO_SRC_LANE1 GENMASK(3, 2) ++ #define TX_CORE_DATA_CAPTURE_2_AFE_FIFO_SRC_LANE0 GENMASK(1, 0) ++ ++#define TX_CORE_DATA_MONITOR_1 0x00F2 ++ #define TX_CORE_DATA_MONITOR_1_LANE1 BIT(7) ++ #define TX_CORE_DATA_MONITOR_1_SELECT_LANE1 GENMASK(6, 4) ++ #define TX_CORE_DATA_MONITOR_1_LANE0 BIT(3) ++ #define TX_CORE_DATA_MONITOR_1_SELECT_LANE0 GENMASK(2, 0) ++ ++#define TX_CORE_DATA_MONITOR_2 0x00F3 ++ #define TX_CORE_DATA_MONITOR_2_MONITOR_SELECT GENMASK(2, 0) ++ ++#define TX_CORE_CALIB_MODE 0x00F4 ++#define TX_CORE_CALIB_SAMPLE_DELAY 0x00F5 ++#define TX_CORE_CALIB_VALUE_AUTO 0x00F6 ++#define TX_CORE_CALIB_VALUE 0x00F7 ++ ++// system config 4 ++#define TX_SYS4_TX_CKI_DDR 0x00A0 ++#define TX_SYS4_TX_CKO_DDR 0x00A1 ++#define TX_SYS4_RX_CKI_DDR 0x00A2 ++#define TX_SYS4_RX_CKO_DDR 0x00A3 ++#define TX_SYS4_CONNECT_SEL_0 0x00A4 ++#define TX_SYS4_CONNECT_SEL_1 0x00A5 ++ #define TX_SYS4_CONNECT_SEL_1_TX_CONNECT_SEL_UPPER_CHANNEL_DATA BIT(6) ++ ++#define TX_SYS4_CONNECT_SEL_2 0x00A6 ++#define TX_SYS4_CONNECT_SEL_3 0x00A7 ++#define TX_SYS4_CK_INV_VIDEO 0x00A8 ++ #define TX_SYS4_CK_INV_VIDEO_TMDS_CLK_PATTERN BIT(4) ++#define TX_SYS4_CK_INV_AUDIO 0x00A9 ++#define TX_SYS4_CK_INV_AFE 0x00AA ++#define TX_SYS4_CK_INV_CH01 0x00AB ++#define TX_SYS4_CK_INV_CH2 0x00AC ++#define TX_SYS4_CK_CEC 0x00AD ++#define TX_SYS4_CK_SOURCE_1 0x00AE ++#define TX_SYS4_CK_SOURCE_2 0x00AF ++ ++#define TX_IEC60958_SUB1_OFFSET 0x00B0 ++#define TX_IEC60958_SUB2_OFFSET 0x00C8 ++ ++// system config 5 ++#define TX_SYS5_TX_SOFT_RESET_1 0x00E0 ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_PIXEL_RSTN BIT(7) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_TMDS_RSTN BIT(6) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_MASTER_RSTN BIT(5) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_AUDIO_RESAMPLE_RSTN BIT(4) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_I2S_RESET_RSTN BIT(3) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH2 BIT(2) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH1 BIT(1) ++ #define TX_SYS5_TX_SOFT_RESET_1_TX_DIG_RESET_N_CH0 BIT(0) ++ ++#define TX_SYS5_TX_SOFT_RESET_2 0x00E1 ++ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH3_RST_IN BIT(7) ++ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH2_RST_IN BIT(6) ++ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH1_RST_IN BIT(5) ++ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_CH0_RST_IN BIT(4) ++ #define TX_SYS5_TX_SOFT_RESET_2_HDMI_SR_RST BIT(3) ++ #define TX_SYS5_TX_SOFT_RESET_2_TX_DDC_HDCP_RSTN BIT(2) ++ #define TX_SYS5_TX_SOFT_RESET_2_TX_DDC_EDID_RSTN BIT(1) ++ #define TX_SYS5_TX_SOFT_RESET_2_TX_DIG_RESET_N_CH3 BIT(0) ++ ++#define TX_SYS5_RX_SOFT_RESET_1 0x00E2 ++#define TX_SYS5_RX_SOFT_RESET_2 0x00E3 ++#define TX_SYS5_RX_SOFT_RESET_3 0x00E4 ++#define TX_SYS5_SSTL_BIDIR_IN 0x00E5 ++#define TX_SYS5_SSTL_IN 0x00E6 ++#define TX_SYS5_SSTL_DIFF_IN 0x00E7 ++#define TX_SYS5_FIFO_CONFIG 0x00E8 ++ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL2_BYPASS BIT(6) ++ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL1_BYPASS BIT(5) ++ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL0_BYPASS BIT(4) ++ #define TX_SYS5_FIFO_CONFIG_CLK_CHANNEL3_OUTPUT_ENABLE BIT(3) ++ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL2_ENABLE BIT(2) ++ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL1_ENABLE BIT(1) ++ #define TX_SYS5_FIFO_CONFIG_AFE_FIFO_CHANNEL0_ENABLE BIT(0) ++ ++#define TX_SYS5_FIFO_SAMP01_CFG 0x00E9 ++#define TX_SYS5_FIFO_SAMP23_CFG 0x00EA ++#define TX_SYS5_CONNECT_FIFO_CFG 0x00EB ++#define TX_SYS5_IO_CALIB_CONTROL 0x00EC ++#define TX_SYS5_SSTL_BIDIR_OUT 0x00ED ++#define TX_SYS5_SSTL_OUT 0x00EE ++#define TX_SYS5_SSTL_DIFF_OUT 0x00EF ++ ++// HDCP shadow register ++#define TX_HDCP_SHW_BKSV_0 0x0100 ++#define TX_HDCP_SHW_BKSV_1 0x0101 ++#define TX_HDCP_SHW_BKSV_2 0x0102 ++#define TX_HDCP_SHW_BKSV_3 0x0103 ++#define TX_HDCP_SHW_BKSV_4 0x0104 ++#define TX_HDCP_SHW_RI1_0 0x0108 ++#define TX_HDCP_SHW_RI1_1 0x0109 ++#define TX_HDCP_SHW_PJ1 0x010A ++#define TX_HDCP_SHW_AKSV_0 0x0110 ++#define TX_HDCP_SHW_AKSV_1 0x0111 ++#define TX_HDCP_SHW_AKSV_2 0x0112 ++#define TX_HDCP_SHW_AKSV_3 0x0113 ++#define TX_HDCP_SHW_AKSV_4 0x0114 ++#define TX_HDCP_SHW_AINFO 0x0115 ++#define TX_HDCP_SHW_AN_0 0x0118 ++#define TX_HDCP_SHW_AN_1 0x0119 ++#define TX_HDCP_SHW_AN_2 0x011A ++#define TX_HDCP_SHW_AN_3 0x011B ++#define TX_HDCP_SHW_AN_4 0x011C ++#define TX_HDCP_SHW_AN_5 0x011D ++#define TX_HDCP_SHW_AN_6 0x011E ++#define TX_HDCP_SHW_AN_7 0x011F ++#define TX_HDCP_SHW_V1_H0_0 0x0120 ++#define TX_HDCP_SHW_V1_H0_1 0x0121 ++#define TX_HDCP_SHW_V1_H0_2 0x0122 ++#define TX_HDCP_SHW_V1_H0_3 0x0123 ++#define TX_HDCP_SHW_V1_H1_0 0x0124 ++#define TX_HDCP_SHW_V1_H1_1 0x0125 ++#define TX_HDCP_SHW_V1_H1_2 0x0126 ++#define TX_HDCP_SHW_V1_H1_3 0x0127 ++#define TX_HDCP_SHW_V1_H2_0 0x0128 ++#define TX_HDCP_SHW_V1_H2_1 0x0129 ++#define TX_HDCP_SHW_V1_H2_2 0x012A ++#define TX_HDCP_SHW_V1_H2_3 0x012B ++#define TX_HDCP_SHW_V1_H3_0 0x012C ++#define TX_HDCP_SHW_V1_H3_1 0x012D ++#define TX_HDCP_SHW_V1_H3_2 0x012E ++#define TX_HDCP_SHW_V1_H3_3 0x012F ++#define TX_HDCP_SHW_V1_H4_0 0x0130 ++#define TX_HDCP_SHW_V1_H4_1 0x0131 ++#define TX_HDCP_SHW_V1_H4_2 0x0132 ++#define TX_HDCP_SHW_V1_H4_3 0x0133 ++#define TX_HDCP_SHW_BCAPS 0x0140 ++#define TX_HDCP_SHW_BSTATUS_0 0x0141 ++#define TX_HDCP_SHW_BSTATUS_1 0x0142 ++#define TX_HDCP_SHW_KSV_FIFO 0x0143 ++ ++// system status 0 ++#define TX_SYSST0_CONNECT_FIFO 0x0180 ++#define TX_SYSST0_PLL_MONITOR 0x0181 ++#define TX_SYSST0_AFE_FIFO 0x0182 ++#define TX_SYSST0_ROM_STATUS 0x018F ++ ++// hdcp status ++#define TX_HDCP_ST_AUTHENTICATION 0x0190 ++#define TX_HDCP_ST_FRAME_COUNT 0x0191 ++#define TX_HDCP_ST_STATUS_0 0x0192 ++#define TX_HDCP_ST_STATUS_1 0x0193 ++#define TX_HDCP_ST_STATUS_2 0x0194 ++#define TX_HDCP_ST_STATUS_3 0x0195 ++#define TX_HDCP_ST_EDID_STATUS 0x0196 ++ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS GENMASK(7, 6) ++ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_NO_SINK_ATTACHED 0x0 ++ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_READING_EDID 0x1 ++ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_DVI_MODE 0x2 ++ #define TX_HDCP_ST_EDID_STATUS_SYSTEM_STATUS_HDMI_MODE 0x3 ++ #define TX_HDCP_ST_EDID_STATUS_EDID_DATA_READY BIT(4) ++ #define TX_HDCP_ST_EDID_STATUS_HPD_STATUS BIT(1) ++ ++#define TX_HDCP_ST_MEM_STATUS 0x0197 ++#define TX_HDCP_ST_ST_MODE 0x019F ++ ++// video status ++#define TX_VIDEO_ST_ACTIVE_PIXELS_1 0x01A0 ++#define TX_VIDEO_ST_ACTIVE_PIXELS_2 0x01A1 ++#define TX_VIDEO_ST_FRONT_PIXELS 0x01A2 ++#define TX_VIDEO_ST_HSYNC_PIXELS 0x01A3 ++#define TX_VIDEO_ST_BACK_PIXELS 0x01A4 ++#define TX_VIDEO_ST_ACTIVE_LINES_1 0x01A5 ++#define TX_VIDEO_ST_ACTIVE_LINES_2 0x01A6 ++#define TX_VIDEO_ST_EOF_LINES 0x01A7 ++#define TX_VIDEO_ST_VSYNC_LINES 0x01A8 ++#define TX_VIDEO_ST_SOF_LINES 0x01A9 ++#define TX_VIDEO_ST_DTV_TIMING 0x01AA ++#define TX_VIDEO_ST_DTV_MODE 0x01AB ++// audio status ++#define TX_VIDEO_ST_AUDIO_STATUS 0x01AC ++#define TX_AFE_STATUS_0 0x01AE ++#define TX_AFE_STATUS_1 0x01AF ++ ++#define TX_IEC60958_ST_SUB1_OFFSET 0x01B0 ++#define TX_IEC60958_ST_SUB2_OFFSET 0x01C8 ++ ++// system status 1 ++#define TX_SYSST1_CALIB_BIT_RESULT_0 0x01E0 ++#define TX_SYSST1_CALIB_BIT_RESULT_1 0x01E1 ++//HDMI_STATUS_OUT[7:0] ++#define TX_HDMI_PHY_READBACK_0 0x01E2 ++//HDMI_COMP_OUT[4] ++//HDMI_STATUS_OUT[11:8] ++#define TX_HDMI_PHY_READBACK_1 0x01E3 ++#define TX_SYSST1_CALIB_BIT_RESULT_4 0x01E4 ++#define TX_SYSST1_CALIB_BIT_RESULT_5 0x01E5 ++#define TX_SYSST1_CALIB_BIT_RESULT_6 0x01E6 ++#define TX_SYSST1_CALIB_BIT_RESULT_7 0x01E7 ++#define TX_SYSST1_CALIB_BUS_RESULT_0 0x01E8 ++#define TX_SYSST1_CALIB_BUS_RESULT_1 0x01E9 ++#define TX_SYSST1_CALIB_BUS_RESULT_2 0x01EA ++#define TX_SYSST1_CALIB_BUS_RESULT_3 0x01EB ++#define TX_SYSST1_CALIB_BUS_RESULT_4 0x01EC ++#define TX_SYSST1_CALIB_BUS_RESULT_5 0x01ED ++#define TX_SYSST1_CALIB_BUS_RESULT_6 0x01EE ++#define TX_SYSST1_CALIB_BUS_RESULT_7 0x01EF ++ ++// Packet status ++#define TX_PACKET_ST_REQUEST_STATUS_1 0x01F0 ++#define TX_PACKET_ST_REQUEST_STATUS_2 0x01F1 ++#define TX_PACKET_ST_REQUEST_MISSED_1 0x01F2 ++#define TX_PACKET_ST_REQUEST_MISSED_2 0x01F3 ++#define TX_PACKET_ST_ENCODE_STATUS_0 0x01F4 ++#define TX_PACKET_ST_ENCODE_STATUS_1 0x01F5 ++#define TX_PACKET_ST_ENCODE_STATUS_2 0x01F6 ++#define TX_PACKET_ST_TIMER_STATUS 0x01F7 ++ ++// tmds status ++#define TX_TMDS_ST_CLOCK_METER_1 0x01F8 ++#define TX_TMDS_ST_CLOCK_METER_2 0x01F9 ++#define TX_TMDS_ST_CLOCK_METER_3 0x01FA ++#define TX_TMDS_ST_TMDS_STATUS_1 0x01FC ++#define TX_TMDS_ST_TMDS_STATUS_2 0x01FD ++#define TX_TMDS_ST_TMDS_STATUS_3 0x01FE ++#define TX_TMDS_ST_TMDS_STATUS_4 0x01FF ++ ++// Packet register ++#define TX_PKT_REG_SPD_INFO_BASE_ADDR 0x0200 ++#define TX_PKT_REG_VEND_INFO_BASE_ADDR 0x0220 ++#define TX_PKT_REG_MPEG_INFO_BASE_ADDR 0x0240 ++#define TX_PKT_REG_AVI_INFO_BASE_ADDR 0x0260 ++#define TX_PKT_REG_AUDIO_INFO_BASE_ADDR 0x0280 ++#define TX_PKT_REG_ACP_INFO_BASE_ADDR 0x02A0 ++#define TX_PKT_REG_ISRC1_BASE_ADDR 0x02C0 ++#define TX_PKT_REG_ISRC2_BASE_ADDR 0x02E0 ++#define TX_PKT_REG_EXCEPT0_BASE_ADDR 0x0300 ++#define TX_PKT_REG_EXCEPT1_BASE_ADDR 0x0320 ++#define TX_PKT_REG_EXCEPT2_BASE_ADDR 0x0340 ++#define TX_PKT_REG_EXCEPT3_BASE_ADDR 0x0360 ++#define TX_PKT_REG_EXCEPT4_BASE_ADDR 0x0380 ++#define TX_PKT_REG_GAMUT_P0_BASE_ADDR 0x03A0 ++#define TX_PKT_REG_GAMUT_P1_1_BASE_ADDR 0x03C0 ++#define TX_PKT_REG_GAMUT_P1_2_BASE_ADDR 0x03E0 ++ ++#define TX_RX_EDID_OFFSET 0x0600 ++ ++/* HDMI OTHER registers */ ++ ++#define HDMI_OTHER_CTRL0 0x8000 ++#define HDMI_OTHER_CTRL1 0x8001 ++ #define HDMI_OTHER_CTRL1_POWER_ON BIT(15) ++ #define HDMI_OTHER_CTRL1_HDMI_AUDIO_CLOCK_ON BIT(13) ++ ++#define HDMI_OTHER_STATUS0 0x8002 ++#define HDMI_OTHER_CTRL2 0x8003 ++#define HDMI_OTHER_INTR_MASKN 0x8004 ++ #define HDMI_OTHER_INTR_MASKN_TX_EDID_INT_RISE BIT(2) ++ #define HDMI_OTHER_INTR_MASKN_TX_HPD_INT_FALL BIT(1) ++ #define HDMI_OTHER_INTR_MASKN_TX_HPD_INT_RISE BIT(0) ++ ++#define HDMI_OTHER_INTR_STAT 0x8005 ++ #define HDMI_OTHER_INTR_STAT_EDID_RISING BIT(2) ++ #define HDMI_OTHER_INTR_STAT_HPD_FALLING BIT(1) ++ #define HDMI_OTHER_INTR_STAT_HPD_RISING BIT(0) ++ ++#define HDMI_OTHER_INTR_STAT_CLR 0x8006 ++ #define HDMI_OTHER_INTR_STAT_CLR_EDID_RISING BIT(2) ++ #define HDMI_OTHER_INTR_STAT_CLR_HPD_FALLING BIT(1) ++ #define HDMI_OTHER_INTR_STAT_CLR_HPD_RISING BIT(0) ++ ++#define HDMI_OTHER_AVI_INTR_MASKN0 0x8008 ++#define HDMI_OTHER_AVI_INTR_MASKN1 0x8009 ++#define HDMI_OTHER_RX_AINFO_INTR_MASKN0 0x800a ++#define HDMI_OTHER_RX_AINFO_INTR_MASKN1 0x800b ++#define HDMI_OTHER_RX_PACKET_INTR_CLR 0x800c ++ ++#endif /* __MESON_TRANSWITCH_HDMI_H__ */ +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0083-drm-meson-Meson8-Meson8b-Meson8m2-VCLK-HACK.patch b/patch/kernel/archive/meson-6.13/0083-drm-meson-Meson8-Meson8b-Meson8m2-VCLK-HACK.patch new file mode 100644 index 000000000000..915944ca6354 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0083-drm-meson-Meson8-Meson8b-Meson8m2-VCLK-HACK.patch @@ -0,0 +1,465 @@ +From d7320d57b6d9cb7741174135a45875d75a50dbd3 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 22:13:51 +0200 +Subject: [PATCH 083/126] drm/meson: Meson8/Meson8b/Meson8m2 VCLK - HACK + +WiP + +Signed-off-by: Martin Blumenstingl +--- + drivers/gpu/drm/meson/meson_drv.c | 95 ++++++++++++++++++- + 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, 290 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index 3a95ba979..99b6773df 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -173,6 +173,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_drm_client_setup(struct meson_drm *priv) + { + /* +@@ -250,10 +279,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; +@@ -268,7 +346,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, +@@ -277,19 +355,19 @@ 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) + goto free_canvas_osd1; +@@ -411,6 +489,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); + free_canvas_osd1: + meson_canvas_free(priv->canvas, priv->canvas_id_osd1); ++video_clock_exit: ++ meson_video_clock_exit(priv); + free_drm: + drm_dev_put(drm); + +@@ -455,6 +535,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 = { +@@ -469,6 +551,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); + } + +@@ -479,6 +563,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 + #include + #include + #include ++#include + + 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 2a942dc6a..a8450f2a0 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0084-drm-meson-Enable-support-for-Meson8-Meson8b-Meson8m2.patch b/patch/kernel/archive/meson-6.13/0084-drm-meson-Enable-support-for-Meson8-Meson8b-Meson8m2.patch new file mode 100644 index 000000000000..f25a63429d28 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0084-drm-meson-Enable-support-for-Meson8-Meson8b-Meson8m2.patch @@ -0,0 +1,52 @@ +From 0888b67819de698786355eae2452b5d1b1c88491 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 25 Apr 2020 22:14:27 +0200 +Subject: [PATCH 084/126] 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 +--- + 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 99b6773df..562435622 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -646,6 +646,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, + }; +@@ -665,6 +677,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0085-ARM-dts-meson-add-the-VPU-WiP.patch b/patch/kernel/archive/meson-6.13/0085-ARM-dts-meson-add-the-VPU-WiP.patch new file mode 100644 index 000000000000..a5be572cb09e --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0085-ARM-dts-meson-add-the-VPU-WiP.patch @@ -0,0 +1,272 @@ +From 42c56f77bd160881471c235b9b6024d030f2c152 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sat, 8 Dec 2018 13:50:48 +0100 +Subject: [PATCH 085/126] ARM: dts: meson: add the VPU - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + 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 763ebfa6a..191aabe49 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 5afd5a8c1..b608bf58c 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 = ; ++ ++ 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 / */ + +@@ -619,6 +684,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>; +@@ -628,6 +704,10 @@ temperature_calib: calib@1f4 { + /* only the upper two bytes are relevant */ + reg = <0x1f4 0x4>; + }; ++ ++ cvbs_trimming: calib@1f8 { ++ reg = <0x1f8 0x2>; ++ }; + }; + + ðmac { +diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi +index 9920175f0..15aa4ecc8 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 = ; ++ ++ 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 / */ + +@@ -388,6 +453,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 { +@@ -549,6 +616,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"; +@@ -559,6 +636,10 @@ temperature_calib: calib@1f4 { + /* only the upper two bytes are relevant */ + reg = <0x1f4 0x4>; + }; ++ ++ cvbs_trimming: calib@1f8 { ++ reg = <0x1f8 0x2>; ++ }; + }; + + ðmac { +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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0086-ARM-dts-meson8-add-the-HDMI-controller-WiP.patch b/patch/kernel/archive/meson-6.13/0086-ARM-dts-meson8-add-the-HDMI-controller-WiP.patch new file mode 100644 index 000000000000..73ceee43fd56 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0086-ARM-dts-meson8-add-the-HDMI-controller-WiP.patch @@ -0,0 +1,125 @@ +From e8b6ff4645eb81932d9ec7a8bbf2c924d009e043 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 5 May 2019 02:30:11 +0200 +Subject: [PATCH 086/126] ARM: dts: meson8: add the HDMI controller - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + 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 b608bf58c..fe162faac 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 = ; ++ 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 / */ +@@ -546,11 +588,26 @@ gpio: bank@80 { + 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; + }; + }; + +@@ -558,7 +615,6 @@ pwm_d_pins: pwm-d { + mux { + groups = "pwm_d"; + function = "pwm_d"; +- bias-disable; + }; + }; + +@@ -742,6 +798,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0087-ARM-dts-meson8-Add-the-shared-CMA-dma-memory-pool.patch b/patch/kernel/archive/meson-6.13/0087-ARM-dts-meson8-Add-the-shared-CMA-dma-memory-pool.patch new file mode 100644 index 000000000000..c8c2513c7174 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0087-ARM-dts-meson8-Add-the-shared-CMA-dma-memory-pool.patch @@ -0,0 +1,36 @@ +From 39c16da64312d0a388e32e1d9dcfd05ab0ab7000 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 4 Jun 2021 21:50:06 +0200 +Subject: [PATCH 087/126] 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 +--- + 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 fe162faac..5f42675f6 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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0088-ARM-dts-meson8-add-the-AO-CEC-controller-WiP.patch b/patch/kernel/archive/meson-6.13/0088-ARM-dts-meson8-add-the-AO-CEC-controller-WiP.patch new file mode 100644 index 000000000000..1fe8281fcd91 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0088-ARM-dts-meson8-add-the-AO-CEC-controller-WiP.patch @@ -0,0 +1,50 @@ +From 16b20604d49a7ab9af9f6e9819b6029494aed256 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 5 May 2019 11:44:08 +0200 +Subject: [PATCH 088/126] ARM: dts: meson8: add the AO CEC controller - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + 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 5f42675f6..e19f11f8a 100644 +--- a/arch/arm/boot/dts/amlogic/meson8.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8.dtsi +@@ -477,6 +477,14 @@ gpio_ao: bank@0 { + 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"; +@@ -541,6 +549,15 @@ mux { + }; + }; + }; ++ ++ cec_AO: cec@100 { ++ compatible = "amlogic,meson-gx-ao-cec"; // FIXME ++ reg = <0x100 0x14>; ++ interrupts = ; ++ // TODO: 32768HZ clock ++ hdmi-phandle = <&hdmi_tx>; ++ status = "disabled"; ++ }; + }; + + &ao_arc_rproc { +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0089-ARM-dts-meson8b-add-the-HDMI-controller-WiP.patch b/patch/kernel/archive/meson-6.13/0089-ARM-dts-meson8b-add-the-HDMI-controller-WiP.patch new file mode 100644 index 000000000000..41038ef924fa --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0089-ARM-dts-meson8b-add-the-HDMI-controller-WiP.patch @@ -0,0 +1,120 @@ +From 6ec08e110c8740257b28aeab53e4832551f7ce8a Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 5 May 2019 02:30:29 +0200 +Subject: [PATCH 089/126] ARM: dts: meson8b: add the HDMI controller - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + 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 15aa4ecc8..97c4f06d5 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 = ; ++ 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 / */ +@@ -540,6 +585,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"; +@@ -702,6 +763,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.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0090-ARM-dts-meson8b-add-the-AO-CEC-controller-WiP.patch b/patch/kernel/archive/meson-6.13/0090-ARM-dts-meson8b-add-the-AO-CEC-controller-WiP.patch new file mode 100644 index 000000000000..06a757194470 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0090-ARM-dts-meson8b-add-the-AO-CEC-controller-WiP.patch @@ -0,0 +1,50 @@ +From da6edd0e70949b34e21811ece223fe2176b07e46 Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Sun, 5 May 2019 11:44:20 +0200 +Subject: [PATCH 090/126] ARM: dts: meson8b: add the AO CEC controller - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + 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 97c4f06d5..5a59a945f 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b.dtsi ++++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi +@@ -434,6 +434,14 @@ gpio_ao: bank@0 { + 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"; +@@ -490,6 +498,15 @@ mux { + }; + }; + }; ++ ++ cec_AO: cec@100 { ++ compatible = "amlogic,meson-gx-ao-cec"; // FIXME ++ reg = <0x100 0x14>; ++ interrupts = ; ++ // TODO: 32768HZ clock ++ hdmi-phandle = <&hdmi_tx>; ++ status = "disabled"; ++ }; + }; + + &ao_arc_rproc { +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/0092-ARM-dts-meson8b-odroid-c1-enable-HDMI-for-the-Odroid.patch b/patch/kernel/archive/meson-6.13/0092-ARM-dts-meson8b-odroid-c1-enable-HDMI-for-the-Odroid.patch new file mode 100644 index 000000000000..1a6375baa5c2 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/0092-ARM-dts-meson8b-odroid-c1-enable-HDMI-for-the-Odroid.patch @@ -0,0 +1,110 @@ +From 5259d423abed4a783621a3aecf560fc8226b38bb Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Fri, 20 Mar 2020 15:17:51 +0100 +Subject: [PATCH 092/126] ARM: dts: meson8b: odroid-c1: enable HDMI for the + Odroid-C1 - WiP + +WiP + +Signed-off-by: Martin Blumenstingl +--- + .../arm/boot/dts/amlogic/meson8b-odroidc1.dts | 62 +++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts b/arch/arm/boot/dts/amlogic/meson8b-odroidc1.dts +index e3841dff0..ca69a96f8 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 { + reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; + }; + ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ + leds { + compatible = "gpio-leds"; + led-blue { +@@ -93,6 +104,41 @@ rtc32k_xtal: rtc32k-xtal-clk { + #clock-cells = <0>; + }; + ++ sound { ++ compatible = "amlogic,gx-sound-card"; ++ model = "ODROID-C1"; ++ ++ clocks = <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ ++ assigned-clocks = <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-rates = <294912000>, ++ <270950400>; ++ ++ dai-link-0 { ++ sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>; ++ }; ++ ++ dai-link-1 { ++ sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>; ++ dai-format = "i2s"; ++ mclk-fs = <256>; ++ ++ codec-0 { ++ sound-dai = <&aiu AIU_HDMI CTRL_I2S>; ++ }; ++ }; ++ ++ dai-link-2 { ++ sound-dai = <&aiu AIU_HDMI CTRL_OUT>; ++ ++ codec-0 { ++ sound-dai = <&hdmi_tx 0>; ++ }; ++ }; ++ }; ++ + usb0_vbus: regulator-usb0-vbus { + /* Richtek RT9715EGB */ + compatible = "regulator-fixed"; +@@ -201,6 +247,10 @@ vdd_rtc: regulator-vdd-rtc { + }; + }; + ++&aiu { ++ status = "okay"; ++}; ++ + &cpu0 { + cpu-supply = <&vcck>; + }; +@@ -297,6 +347,18 @@ &gpio_ao { + "SYS_LED", "", ""; + }; + ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ + &ir_receiver { + status = "okay"; + pinctrl-0 = <&ir_recv_pins>; +-- +2.48.1 + diff --git a/patch/kernel/archive/meson-6.13/generic-Revert-mmc-core-Set-HS-clock-speed-before-sending-HS-CMD13.patch b/patch/kernel/archive/meson-6.13/generic-Revert-mmc-core-Set-HS-clock-speed-before-sending-HS-CMD13.patch new file mode 100644 index 000000000000..aca6b585a17d --- /dev/null +++ b/patch/kernel/archive/meson-6.13/generic-Revert-mmc-core-Set-HS-clock-speed-before-sending-HS-CMD13.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hzy +Date: Sat, 18 Nov 2023 01:22:04 +0800 +Subject: Revert "mmc: core: Set HS clock speed before sending HS CMD13" + +This reverts commit 4bc31edebde51fcf8ad0794763b8679a7ecb5ec0. +--- + drivers/mmc/core/mmc.c | 23 ++-------- + 1 file changed, 4 insertions(+), 19 deletions(-) + +diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c +index 111111111111..222222222222 100644 +--- a/drivers/mmc/core/mmc.c ++++ b/drivers/mmc/core/mmc.c +@@ -1401,17 +1401,13 @@ static int mmc_select_hs400es(struct mmc_card *card) + goto out_err; + } + +- /* +- * Bump to HS timing and frequency. Some cards don't handle +- * SEND_STATUS reliably at the initial frequency. +- */ + mmc_set_timing(host, MMC_TIMING_MMC_HS); +- mmc_set_bus_speed(card); +- + err = mmc_switch_status(card, true); + if (err) + goto out_err; + ++ mmc_set_clock(host, card->ext_csd.hs_max_dtr); ++ + /* Switch card to DDR with strobe bit */ + val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE; + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, +@@ -1469,7 +1465,7 @@ static int mmc_select_hs400es(struct mmc_card *card) + static int mmc_select_hs200(struct mmc_card *card) + { + struct mmc_host *host = card->host; +- unsigned int old_timing, old_signal_voltage, old_clock; ++ unsigned int old_timing, old_signal_voltage; + int err = -EINVAL; + u8 val; + +@@ -1500,17 +1496,8 @@ static int mmc_select_hs200(struct mmc_card *card) + false, true, MMC_CMD_RETRIES); + if (err) + goto err; +- +- /* +- * Bump to HS timing and frequency. Some cards don't handle +- * SEND_STATUS reliably at the initial frequency. +- * NB: We can't move to full (HS200) speeds until after we've +- * successfully switched over. +- */ + old_timing = host->ios.timing; +- old_clock = host->ios.clock; + mmc_set_timing(host, MMC_TIMING_MMC_HS200); +- mmc_set_clock(card->host, card->ext_csd.hs_max_dtr); + + /* + * For HS200, CRC errors are not a reliable way to know the +@@ -1523,10 +1510,8 @@ static int mmc_select_hs200(struct mmc_card *card) + * mmc_select_timing() assumes timing has not changed if + * it is a switch error. + */ +- if (err == -EBADMSG) { +- mmc_set_clock(host, old_clock); ++ if (err == -EBADMSG) + mmc_set_timing(host, old_timing); +- } + } + err: + if (err) { +-- +Armbian + diff --git a/patch/kernel/archive/meson-6.13/generic-Revert-pwm-meson-modify-and-simplify-calculation-in-.patch b/patch/kernel/archive/meson-6.13/generic-Revert-pwm-meson-modify-and-simplify-calculation-in-.patch new file mode 100644 index 000000000000..848cd3e4d562 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/generic-Revert-pwm-meson-modify-and-simplify-calculation-in-.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hzy +Date: Sat, 18 Nov 2023 01:22:04 +0800 +Subject: Revert "pwm: meson: modify and simplify calculation in + meson_pwm_get_state" + +This reverts commit 6b9352f3f8a1a35faf0efc1ad1807ee303467796. +--- + drivers/pwm/pwm-meson.c | 14 ++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c +index 111111111111..222222222222 100644 +--- a/drivers/pwm/pwm-meson.c ++++ b/drivers/pwm/pwm-meson.c +@@ -322,8 +322,18 @@ static int meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + channel->lo = FIELD_GET(PWM_LOW_MASK, value); + channel->hi = FIELD_GET(PWM_HIGH_MASK, value); + +- state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->lo + channel->hi); +- state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, channel->hi); ++ if (channel->lo == 0) { ++ state->period = meson_pwm_cnt_to_ns(chip, pwm, channel->hi); ++ state->duty_cycle = state->period; ++ } else if (channel->lo >= channel->hi) { ++ state->period = meson_pwm_cnt_to_ns(chip, pwm, ++ channel->lo + channel->hi); ++ state->duty_cycle = meson_pwm_cnt_to_ns(chip, pwm, ++ channel->hi); ++ } else { ++ state->period = 0; ++ state->duty_cycle = 0; ++ } + + state->polarity = PWM_POLARITY_NORMAL; + +-- +Armbian + diff --git a/patch/kernel/archive/meson-6.13/onecloud-0001-add-dts.patch b/patch/kernel/archive/meson-6.13/onecloud-0001-add-dts.patch new file mode 100644 index 000000000000..b9d9cc535d1a --- /dev/null +++ b/patch/kernel/archive/meson-6.13/onecloud-0001-add-dts.patch @@ -0,0 +1,440 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hzy +Date: Sat, 1 Apr 2023 13:24:42 +0800 +Subject: ARM: dts: meson8b: Add DTS for Xunlei Onecloud + +Signed-off-by: hzy +--- + arch/arm/boot/dts/amlogic/Makefile | 1 + + arch/arm/boot/dts/amlogic/meson8b-onecloud.dts | 410 ++++++++++ + 2 files changed, 411 insertions(+) + +diff --git a/arch/arm/boot/dts/amlogic/Makefile b/arch/arm/boot/dts/amlogic/Makefile +index 111111111111..222222222222 100644 +--- a/arch/arm/boot/dts/amlogic/Makefile ++++ b/arch/arm/boot/dts/amlogic/Makefile +@@ -6,4 +6,5 @@ dtb-$(CONFIG_MACH_MESON8) += \ + meson8b-ec100.dtb \ + meson8b-mxq.dtb \ + meson8b-odroidc1.dtb \ ++ meson8b-onecloud.dtb \ + meson8m2-mxiii-plus.dtb +diff --git a/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts b/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts +new file mode 100644 +index 000000000000..111111111111 +--- /dev/null ++++ b/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts +@@ -0,0 +1,410 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Author: hzy ++ */ ++ ++/dts-v1/; ++ ++#include "meson8b.dtsi" ++#include ++#include ++ ++/ { ++ model = "Xunlei OneCloud"; ++ compatible = "xunlei,onecloud", "amlogic,meson8b"; ++ ++ aliases { ++ serial0 = &uart_AO; ++ mmc0 = &sd_card_slot; ++ mmc1 = &sdhc; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x40000000 0x40000000>; ++ }; ++ ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; ++ }; ++ ++ button { ++ // compatible = "gpio-keys-polled"; ++ // poll-interval = <100>; ++ ++ compatible = "gpio-keys"; ++ ++ autorepeat; ++ ++ reset-button { ++ label = "reset"; ++ linux,code = ; ++ ++ // gpios = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_LOW>; ++ ++ interrupt-parent = <&gpio_intc>; ++ interrupts = <5 IRQ_TYPE_LEVEL_LOW>; // GPIOAO 5 ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ red { ++ label = "onecloud:red:alive"; ++ gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_HIGH>; ++ ++ default-state = "on"; ++ linux,default-trigger = "default-on"; ++ }; ++ ++ green { ++ label = "onecloud:green:alive"; ++ gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>; ++ ++ default-state = "off"; ++ linux,default-trigger = "mmc1"; ++ }; ++ ++ blue { ++ label = "onecloud:blue:alive"; ++ gpios = <&gpio_ao GPIOAO_4 GPIO_ACTIVE_HIGH>; ++ ++ default-state = "off"; ++ linux,default-trigger = "usb-host"; ++ }; ++ }; ++ ++ p12v: regulator-p12v { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "P12V"; ++ regulator-min-microvolt = <12000000>; ++ regulator-max-microvolt = <12000000>; ++ }; ++ ++ vcc_5v: regulator-vcc-5v { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "VCC5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ ++ vin-supply = <&p12v>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc-3v3 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "VCC3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ ++ vin-supply = <&p12v>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vcc_1v8: regulator-vcc-1v8 { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "VCC1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ ++ vin-supply = <&p12v>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vcc_ddr: regulator-vcc-ddr { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "VCC_DDR"; ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <1500000>; ++ ++ vin-supply = <&vcc_3v3>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vcc_core: regulator-vcc-core { ++ compatible = "pwm-regulator"; ++ ++ regulator-name = "VCC_CORE"; ++ ++ // +---------------------------------------------------+ ++ // | The actual mapping in phyical | ++ // +------+--------+--------+--------+--------+--------+ ++ // | | 100% | 60% | 30% | 10% | 0% | ++ // +------+--------+--------+--------+--------+--------+ ++ // | V1.0 | 677mV | 857mV | 992mV | 1082mV | 1127mV | ++ // | V1.3 | 1116mV | 1121mV | 1125mV | 1128mV | 1129mV | ++ // +------+--------+--------+--------+--------+--------+ ++ // ++ // According to meson8b.dtsi, the CPU should be able to ++ // run at 504MHz with 870mV. But this regulator supplies ++ // not only CPU but also GPU. And according to the users' ++ // tests on V1.0, we need such higher voltages. ++ ++ pwms = <&pwm_cd 1 12001 0>; // PWM_D ++ pwm-dutycycle-range = <10 0>; ++ regulator-min-microvolt = <860000>; ++ regulator-max-microvolt = <1140000>; ++ ++ pwm-supply = <&p12v>; ++ ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&pwm_cd { ++ status = "okay"; ++ pinctrl-0 = <&pwm_c1_pins>, <&pwm_d_pins>; ++ pinctrl-names = "default"; ++ clocks = <&xtal>, <&xtal>; ++ clock-names = "clkin0", "clkin1"; ++}; ++ ++&cpu0 { ++ cpu-supply = <&vcc_core>; ++}; ++ ++&saradc { ++ status = "okay"; ++ vref-supply = <&vcc_1v8>; ++}; ++ ++&mali { ++ // commented to allow cpufreq tweaking ++ // mali-supply = <&vcc_core>; ++}; ++ ++&gpio { ++ gpio-line-names = ++ /* 0 */ "WIFI_SDIO_D0 PIN18 (GPIOX_0)", ++ /* 1 */ "WIFI_SDIO_D1 PIN19 (GPIOX_1)", ++ /* 2 */ "WIFI_SDIO_D2 PIN14 (GPIOX_2)", ++ /* 3 */ "WIFI_SDIO_D3 PIN15 (GPIOX_3)", ++ /* 4 */ "WIFI_PCM_DIN PIN27 (GPIOX_4)", ++ /* 5 */ "WIFI_PCM_DOUT PIN25 (GPIOX_5)", ++ /* 6 */ "WIFI_PCM_SYNC PIN28 (GPIOX_6)", ++ /* 7 */ "WIFI_PCM_CLK PIN26 (GPIOX_7)", ++ /* 8 */ "WIFI_SDIO_CLK PIN17_Resistor (GPIOX_8)", ++ /* 9 */ "WIFI_SDIO_CMD PIN16 (GPIOX_9)", ++ /* 10 */ "GPIOX_10", ++ /* 11 */ "WIFI PIN12 (GPIOX_11)", ++ /* 12 */ "WIFI_UART_RX PIN43 (GPIOX_16)", ++ /* 13 */ "WIFI_UART_TX PIN42 (GPIOX_17)", ++ /* 14 */ "WIFI_UART_RTS PIN41_Resistor (GPIOX_18)", ++ /* 15 */ "WIFI_UART_CTS PIN44 (GPIOX_19)", ++ /* 16 */ "WIFI PIN34 (GPIOX_20)", ++ /* 17 */ "WIFI_WAKE PIN13 (GPIOX_21)", ++ ++ /* 18 */ "Resistor_TopOf_LED (GPIOY_0)", ++ /* 19 */ "GPIOY_1", ++ /* 20 */ "GPIOY_3", ++ /* 21 */ "GPIOY_6", ++ /* 22 */ "GPIOY_7", ++ /* 23 */ "GPIOY_8", ++ /* 24 */ "GPIOY_9", ++ /* 25 */ "GPIOY_10", ++ /* 26 */ "GPIOY_11", ++ /* 27 */ "GPIOY_12", ++ /* 28 */ "Left_BottomOf_CPU (GPIOY_13)", ++ /* 29 */ "Right_BottomOf_CPU (GPIOY_14)", ++ ++ /* 30 */ "GPIODV_9 (PWM_C)", ++ /* 31 */ "GPIODV_24", ++ /* 32 */ "GPIODV_25", ++ /* 33 */ "GPIODV_26", ++ /* 34 */ "GPIODV_27", ++ /* 35 */ "VCC_CPU_PWM (GPIODV_28)", ++ /* 36 */ "GPIODV_29", ++ ++ /* 37 */ "HDMI_HPD (GPIOH_0)", ++ /* 38 */ "HDMI_SDA (GPIOH_1)", ++ /* 39 */ "HDMI_SCL (GPIOH_2)", ++ /* 40 */ "ETH_PHY_INTR (GPIOH_3)", ++ /* 41 */ "ETH_PHY_nRST (GPIOH_4)", ++ /* 42 */ "ETH_TXD1 (GPIOH_5)", ++ /* 43 */ "ETH_TXD0 (GPIOH_6)", ++ /* 44 */ "ETH_TXD3 (GPIOH_7)", ++ /* 45 */ "ETH_TXD2 (GPIOH_8)", ++ /* 46 */ "ETH_TX_CLK (GPIOH_9)", ++ ++ /* 47 */ "SDCARD_D1 (CARD_0)", ++ /* 48 */ "SDCARD_D0 (CARD_1)", ++ /* 49 */ "SDCARD_CLK (CARD_2)", ++ /* 50 */ "SDCARD_CMD (CARD_3)", ++ /* 51 */ "SDCARD_D3 (CARD_4)", ++ /* 52 */ "SDCARD_D2 (CARD_5)", ++ /* 53 */ "SDCARD_CD (CARD_6)", ++ ++ /* 54 */ "EMMC_D0 (BOOT_0)", ++ /* 55 */ "EMMC_D1 (BOOT_1)", ++ /* 56 */ "EMMC_D2 (BOOT_2)", ++ /* 57 */ "EMMC_D3 (BOOT_3)", ++ /* 58 */ "EMMC_D4 (BOOT_4)", ++ /* 59 */ "EMMC_D5 (BOOT_5)", ++ /* 60 */ "EMMC_D6 (BOOT_6)", ++ /* 61 */ "EMMC_D7 (BOOT_7)", ++ /* 62 */ "EMMC_CLK (BOOT_8)", ++ /* 63 */ "EMMC_nRST (BOOT_9)", ++ /* 64 */ "EMMC_CMD (BOOT_10)", ++ /* 65 */ "BOOT_11", ++ /* 66 */ "BOOT_12", ++ /* 67 */ "BOOT_13", ++ /* 68 */ "BOOT_14", ++ /* 69 */ "BOOT_15", ++ /* 70 */ "BOOT_16", ++ /* 71 */ "BOOT_17", ++ /* 72 */ "BOOT_18", ++ ++ /* 73 */ "ETH_RXD1 (DIF_0_P)", ++ /* 74 */ "ETH_RXD0 (DIF_0_N)", ++ /* 75 */ "ETH_RX_DV (DIF_1_P)", ++ /* 76 */ "ETH_RX_CLK (DIF_1_N)", ++ /* 77 */ "ETH_RXD3 (DIF_2_P)", ++ /* 78 */ "ETH_RXD2 (DIF_2_N)", ++ /* 79 */ "ETH_TX_EN (DIF_3_P)", ++ /* 80 */ "ETH_REF_CLK (DIF_3_N)", ++ /* 81 */ "ETH_MDC (DIF_4_P)", ++ /* 82 */ "ETH_MDIO_EN (DIF_4_N)"; ++}; ++ ++&gpio_ao { ++ gpio-line-names = ++ /* 0 */ "UART TX (GPIOAO_0)", ++ /* 1 */ "UART RX (GPIOAO_1)", ++ /* 2 */ "RED_LED (GPIOAO_2)", ++ /* 3 */ "GREEN_LED (GPIOAO_3)", ++ /* 4 */ "BLUE_LED (GPIOAO_4)", ++ /* 5 */ "BUTTON (GPIOAO_5)", ++ /* 6 */ "GPIOAO_6", ++ /* 7 */ "IR_IN (GPIOAO_7)", ++ /* 8 */ "GPIOAO_8", ++ /* 9 */ "GPIOAO_9", ++ /* 10 */ "GPIOAO_10", ++ /* 11 */ "GPIOAO_11", ++ /* 12 */ "GPIOAO_12", ++ /* 13 */ "GPIOAO_13", ++ ++ /* 14 */ "GPIO_BSD_EN", ++ /* 15 */ "GPIO_TEST_N"; ++}; ++ ++// eMMC ++&sdhc { ++ status = "okay"; ++ ++ pinctrl-0 = <&sdxc_c_pins>; ++ pinctrl-names = "default"; ++ ++ non-removable; ++ bus-width = <8>; ++ max-frequency = <200000000>; ++ cap-mmc-highspeed; ++ mmc-hs200-1_8v; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ // vqmmc-supply = <&vcc_3v3>; ++}; ++ ++&sdio { ++ status = "okay"; ++ ++ pinctrl-0 = <&sd_b_pins>; ++ pinctrl-names = "default"; ++ ++ // SD card ++ sd_card_slot: slot@1 { ++ compatible = "mmc-slot"; ++ reg = <1>; ++ status = "okay"; ++ ++ bus-width = <4>; ++ no-sdio; ++ cap-mmc-highspeed; ++ cap-sd-highspeed; ++ disable-wp; ++ ++ cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; ++ ++ vmmc-supply = <&vcc_3v3>; ++ // vqmmc-supply = <&vcc_3v3>; ++ }; ++}; ++ ++ðmac { ++ status = "okay"; ++ ++ pinctrl-0 = <ð_rgmii_pins>; ++ pinctrl-names = "default"; ++ ++ phy-handle = <ð_phy>; ++ phy-mode = "rgmii-rxid"; ++ ++ mdio { ++ compatible = "snps,dwmac-mdio"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ // Realtek RTL8211F (0x001cc916) ++ eth_phy: ethernet-phy@0 { ++ reg = <0>; ++ ++ reset-assert-us = <10000>; ++ reset-deassert-us = <80000>; ++ reset-gpios = <&gpio GPIOH_4 GPIO_ACTIVE_LOW>; ++ ++ interrupt-parent = <&gpio_intc>; ++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>; // GPIOH 3 ++ }; ++ }; ++}; ++ ++&usb0 { ++ status = "okay"; ++ dr_mode = "otg"; ++ usb-role-switch; ++ role-switch-default-mode = "host"; ++}; ++ ++&usb0_phy { ++ status = "okay"; ++}; ++ ++&usb1 { ++ status = "okay"; ++}; ++ ++&usb1_phy { ++ status = "okay"; ++}; ++ ++&ir_receiver { ++ status = "okay"; ++ pinctrl-0 = <&ir_recv_pins>; ++ pinctrl-names = "default"; ++}; +-- +Armbian + diff --git a/patch/kernel/archive/meson-6.13/onecloud-0002-dts-Support-HDMI.patch b/patch/kernel/archive/meson-6.13/onecloud-0002-dts-Support-HDMI.patch new file mode 100644 index 000000000000..597a2676b2c1 --- /dev/null +++ b/patch/kernel/archive/meson-6.13/onecloud-0002-dts-Support-HDMI.patch @@ -0,0 +1,96 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hzy +Date: Sat, 1 Apr 2023 10:26:14 +0800 +Subject: ARM: dts: meson8b: onecloud: Support HDMI + +Signed-off-by: hzy +--- + arch/arm/boot/dts/amlogic/meson8b-onecloud.dts | 58 ++++++++++ + 1 file changed, 58 insertions(+) + +diff --git a/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts b/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts +index 111111111111..222222222222 100644 +--- a/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts ++++ b/arch/arm/boot/dts/amlogic/meson8b-onecloud.dts +@@ -80,6 +80,48 @@ blue { + }; + }; + ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ ++ sound { ++ compatible = "amlogic,gx-sound-card"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-rates = <294912000>, ++ <270950400>; ++ ++ dai-link-0 { ++ sound-dai = <&aiu AIU_CPU CPU_I2S_FIFO>; ++ }; ++ ++ dai-link-1 { ++ sound-dai = <&aiu AIU_CPU CPU_I2S_ENCODER>; ++ dai-format = "i2s"; ++ mclk-fs = <256>; ++ ++ codec-0 { ++ sound-dai = <&aiu AIU_HDMI CTRL_I2S>; ++ }; ++ }; ++ ++ dai-link-2 { ++ sound-dai = <&aiu AIU_HDMI CTRL_OUT>; ++ ++ codec-0 { ++ sound-dai = <&hdmi_tx 0>; ++ }; ++ }; ++ }; ++ + p12v: regulator-p12v { + compatible = "regulator-fixed"; + +@@ -199,6 +241,10 @@ &mali { + // mali-supply = <&vcc_core>; + }; + ++&aiu { ++ status = "okay"; ++}; ++ + &gpio { + gpio-line-names = + /* 0 */ "WIFI_SDIO_D0 PIN18 (GPIOX_0)", +@@ -403,6 +449,18 @@ &usb1_phy { + status = "okay"; + }; + ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ + &ir_receiver { + status = "okay"; + pinctrl-0 = <&ir_recv_pins>; +-- +Armbian +