diff options
| author | Adrian Betschart <adrian.betschart@cinemaone.ch> | 2026-09-11 17:13:14 +0200 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-10-01 17:18:05 -0400 |
| commit | 106b4a2a78b2a2f14885604891957b84bba502db (patch) | |
| tree | 5d40eef2428fb1a4791ab46a4b19091a5910eac2 /drivers/bluetooth/btrsi.c | |
| download | linux-stable-106b4a2a78b2a2f14885604891957b84bba502db.tar.gz linux-stable-106b4a2a78b2a2f14885604891957b84bba502db.zip | |
drm/amd/display: Try RGB before YCbCr 4:4:4 in stream validationgrafted
amdgpu_dm_create_validate_stream_for_sink() walks encoding_order[] and
uses the first encoding that validates. YCbCr 4:4:4 is listed before
RGB, so an HDMI sink that advertises 4:4:4 gets YCbCr 4:4:4 whenever the
"color format" property is left at AUTO, even though RGB fits the same
link.
That contradicts the documented AUTO behaviour for HDMI in enum
drm_connector_color_format (RGB, falling back to YCbCr 4:2:0 only when
the bandwidth is not available or the mode is 4:2:0-only), which the
amdgpu implementation of the property also describes. It also leaves
the "Broadcast RGB" property without effect on such sinks, since the
quantization range it selects only applies to RGB output.
Try RGB first. The mask still holds every encoding the sink supports,
so a mode that cannot carry RGB falls back exactly as before.
For reference, v7.2 picked RGB here unless YCbCr 4:4:4 was forced
through debugfs, while earlier kernels picked YCbCr 4:4:4 for any HDMI
sink that advertised it.
Fixes: 0b0ff65d3ca1 ("drm/amd/display: Refactor stream validation")
Suggested-by: Adolfo Rodrigues <adolfotregosa@gmail.com>
Assisted-by: Claude Code:claude-fable-5-1
Signed-off-by: Adrian Betschart <adrian.betschart@cinemaone.ch>
Reviewed-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Adolfo Rodrigues <adolfotregosa@gmail.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 7de432bc753133764dc40d37f9388da56de251e7)
Diffstat (limited to 'drivers/bluetooth/btrsi.c')
| -rw-r--r-- | drivers/bluetooth/btrsi.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/drivers/bluetooth/btrsi.c b/drivers/bluetooth/btrsi.c new file mode 100644 index 000000000..3f802b7c8 --- /dev/null +++ b/drivers/bluetooth/btrsi.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2017 Redpine Signals Inc. + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> +#include <linux/unaligned.h> +#include <net/rsi_91x.h> + +#define RSI_DMA_ALIGN 8 +#define RSI_FRAME_DESC_SIZE 16 +#define RSI_HEADROOM_FOR_BT_HAL (RSI_FRAME_DESC_SIZE + RSI_DMA_ALIGN) + +struct rsi_hci_adapter { + void *priv; + struct rsi_proto_ops *proto_ops; + struct hci_dev *hdev; +}; + +static int rsi_hci_open(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_close(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_flush(struct hci_dev *hdev) +{ + return 0; +} + +static int rsi_hci_send_pkt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct rsi_hci_adapter *h_adapter = hci_get_drvdata(hdev); + struct sk_buff *new_skb = NULL; + + switch (hci_skb_pkt_type(skb)) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + } + + if (skb_headroom(skb) < RSI_HEADROOM_FOR_BT_HAL) { + /* Insufficient skb headroom - allocate a new skb */ + new_skb = skb_realloc_headroom(skb, RSI_HEADROOM_FOR_BT_HAL); + if (unlikely(!new_skb)) + return -ENOMEM; + bt_cb(new_skb)->pkt_type = hci_skb_pkt_type(skb); + kfree_skb(skb); + skb = new_skb; + if (!IS_ALIGNED((unsigned long)skb->data, RSI_DMA_ALIGN)) { + u8 *skb_data = skb->data; + int skb_len = skb->len; + + skb_push(skb, RSI_DMA_ALIGN); + skb_pull(skb, PTR_ALIGN(skb->data, + RSI_DMA_ALIGN) - skb->data); + memmove(skb->data, skb_data, skb_len); + skb_trim(skb, skb_len); + } + } + + return h_adapter->proto_ops->coex_send_pkt(h_adapter->priv, skb, + RSI_BT_Q); +} + +static int rsi_hci_recv_pkt(void *priv, const u8 *pkt) +{ + struct rsi_hci_adapter *h_adapter = priv; + struct hci_dev *hdev = h_adapter->hdev; + struct sk_buff *skb; + int pkt_len = get_unaligned_le16(pkt) & 0x0fff; + + skb = dev_alloc_skb(pkt_len); + if (!skb) + return -ENOMEM; + + memcpy(skb->data, pkt + RSI_FRAME_DESC_SIZE, pkt_len); + skb_put(skb, pkt_len); + h_adapter->hdev->stat.byte_rx += skb->len; + + hci_skb_pkt_type(skb) = pkt[14]; + + return hci_recv_frame(hdev, skb); +} + +static int rsi_hci_attach(void *priv, struct rsi_proto_ops *ops) +{ + struct rsi_hci_adapter *h_adapter = NULL; + struct hci_dev *hdev; + int err = 0; + + h_adapter = kzalloc_obj(*h_adapter); + if (!h_adapter) + return -ENOMEM; + + h_adapter->priv = priv; + h_adapter->proto_ops = ops; + + hdev = hci_alloc_dev(); + if (!hdev) { + BT_ERR("Failed to alloc HCI device"); + goto err; + } + + h_adapter->hdev = hdev; + + if (ops->get_host_intf(priv) == RSI_HOST_INTF_SDIO) + hdev->bus = HCI_SDIO; + else + hdev->bus = HCI_USB; + + hci_set_drvdata(hdev, h_adapter); + hdev->open = rsi_hci_open; + hdev->close = rsi_hci_close; + hdev->flush = rsi_hci_flush; + hdev->send = rsi_hci_send_pkt; + + err = hci_register_dev(hdev); + if (err < 0) { + BT_ERR("HCI registration failed with errcode %d", err); + hci_free_dev(hdev); + goto err; + } + + ops->set_bt_context(priv, h_adapter); + + return 0; +err: + h_adapter->hdev = NULL; + kfree(h_adapter); + return -EINVAL; +} + +static void rsi_hci_detach(void *priv) +{ + struct rsi_hci_adapter *h_adapter = priv; + struct hci_dev *hdev; + + if (!h_adapter) + return; + + hdev = h_adapter->hdev; + if (hdev) { + hci_unregister_dev(hdev); + hci_free_dev(hdev); + h_adapter->hdev = NULL; + } + + kfree(h_adapter); +} + +const struct rsi_mod_ops rsi_bt_ops = { + .attach = rsi_hci_attach, + .detach = rsi_hci_detach, + .recv_pkt = rsi_hci_recv_pkt, +}; +EXPORT_SYMBOL(rsi_bt_ops); + +static int rsi_91x_bt_module_init(void) +{ + return 0; +} + +static void rsi_91x_bt_module_exit(void) +{ + return; +} + +module_init(rsi_91x_bt_module_init); +module_exit(rsi_91x_bt_module_exit); +MODULE_AUTHOR("Redpine Signals Inc"); +MODULE_DESCRIPTION("RSI BT driver"); +MODULE_LICENSE("Dual BSD/GPL"); |
