FILE
imx8mp-hdmi-pai.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pai.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2025 NXP 4 */ 5 6#include <linux/bitfield.h> 7#include <linux/component.h> 8#include <linux/module.h> 9#include <linux/of_platform.h> 10#include <linux/platform_device.h> 11#include <linux/pm_runtime.h> 12#include <linux/regmap.h> 13#include <drm/bridge/dw_hdmi.h> 14#include <sound/asoundef.h> 15 16#define HTX_PAI_CTRL 0x00 17#define ENABLE BIT(0) 18 19#define HTX_PAI_CTRL_EXT 0x04 20#define WTMK_HIGH_MASK GENMASK(31, 24) 21#define WTMK_LOW_MASK GENMASK(23, 16) 22#define NUM_CH_MASK GENMASK(10, 8) 23#define WTMK_HIGH(n) FIELD_PREP(WTMK_HIGH_MASK, (n)) 24#define WTMK_LOW(n) FIELD_PREP(WTMK_LOW_MASK, (n)) 25#define NUM_CH(n) FIELD_PREP(NUM_CH_MASK, (n) - 1) 26 27#define HTX_PAI_FIELD_CTRL 0x08 28#define PRE_SEL GENMASK(28, 24) 29#define D_SEL GENMASK(23, 20) 30#define V_SEL GENMASK(19, 15) 31#define U_SEL GENMASK(14, 10) 32#define C_SEL GENMASK(9, 5) 33#define P_SEL GENMASK(4, 0) 34 35struct imx8mp_hdmi_pai { 36 struct regmap *regmap; 37 struct device *dev; 38}; 39 40static void imx8mp_hdmi_pai_enable(struct dw_hdmi *dw_hdmi, int channel, 41 int width, int rate, int non_pcm, 42 int iec958) 43{ 44 const struct dw_hdmi_plat_data *pdata = dw_hdmi_to_plat_data(dw_hdmi); 45 struct imx8mp_hdmi_pai *hdmi_pai = pdata->priv_audio; 46 int val; 47 48 if (pm_runtime_resume_and_get(hdmi_pai->dev) < 0) 49 return; 50 51 /* PAI set control extended */ 52 val = WTMK_HIGH(3) | WTMK_LOW(3); 53 val |= NUM_CH(channel); 54 regmap_write(hdmi_pai->regmap, HTX_PAI_CTRL_EXT, val); 55 56 /* IEC60958 format */ 57 if (iec958) { 58 val = FIELD_PREP_CONST(P_SEL, 59 __bf_shf(IEC958_SUBFRAME_PARITY)); 60 val |= FIELD_PREP_CONST(C_SEL, 61 __bf_shf(IEC958_SUBFRAME_CHANNEL_STATUS)); 62 val |= FIELD_PREP_CONST(U_SEL, 63 __bf_shf(IEC958_SUBFRAME_USER_DATA)); 64 val |= FIELD_PREP_CONST(V_SEL, 65 __bf_shf(IEC958_SUBFRAME_VALIDITY)); 66 val |= FIELD_PREP_CONST(D_SEL, 67 __bf_shf(IEC958_SUBFRAME_SAMPLE_24_MASK)); 68 val |= FIELD_PREP_CONST(PRE_SEL, 69 __bf_shf(IEC958_SUBFRAME_PREAMBLE_MASK)); 70 } else { 71 /* 72 * The allowed PCM widths are 24bit and 32bit, as they are supported 73 * by aud2htx module. 74 * for 24bit, D_SEL = 0, select all the bits. 75 * for 32bit, D_SEL = 8, select 24bit in MSB. 76 */ 77 val = FIELD_PREP(D_SEL, width - 24); 78 } 79 80 regmap_write(hdmi_pai->regmap, HTX_PAI_FIELD_CTRL, val); 81 82 /* PAI start running */ 83 regmap_write(hdmi_pai->regmap, HTX_PAI_CTRL, ENABLE); 84} 85 86static void imx8mp_hdmi_pai_disable(struct dw_hdmi *dw_hdmi) 87{ 88 const struct dw_hdmi_plat_data *pdata = dw_hdmi_to_plat_data(dw_hdmi); 89 struct imx8mp_hdmi_pai *hdmi_pai = pdata->priv_audio; 90 91 /* Stop PAI */ 92 regmap_write(hdmi_pai->regmap, HTX_PAI_CTRL, 0); 93 94 pm_runtime_put_sync(hdmi_pai->dev); 95} 96 97static const struct regmap_config imx8mp_hdmi_pai_regmap_config = { 98 .reg_bits = 32, 99 .reg_stride = 4, 100 .val_bits = 32, 101 .max_register = HTX_PAI_FIELD_CTRL, 102}; 103 104static int imx8mp_hdmi_pai_bind(struct device *dev, struct device *master, void *data) 105{ 106 struct platform_device *pdev = to_platform_device(dev); 107 struct dw_hdmi_plat_data *plat_data = data; 108 struct imx8mp_hdmi_pai *hdmi_pai; 109 struct resource *res; 110 void __iomem *base; 111 int ret; 112 113 hdmi_pai = devm_kzalloc(dev, sizeof(*hdmi_pai), GFP_KERNEL); 114 if (!hdmi_pai) 115 return -ENOMEM; 116 117 base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 118 if (IS_ERR(base)) 119 return PTR_ERR(base); 120 121 hdmi_pai->regmap = devm_regmap_init_mmio_clk(dev, "apb", base, 122 &imx8mp_hdmi_pai_regmap_config); 123 if (IS_ERR(hdmi_pai->regmap)) { 124 dev_err(dev, "regmap init failed\n"); 125 return PTR_ERR(hdmi_pai->regmap); 126 } 127 128 plat_data->enable_audio = imx8mp_hdmi_pai_enable; 129 plat_data->disable_audio = imx8mp_hdmi_pai_disable; 130 plat_data->priv_audio = hdmi_pai; 131 132 hdmi_pai->dev = dev; 133 ret = devm_pm_runtime_enable(dev); 134 if (ret < 0) { 135 dev_err(dev, "failed to enable PM runtime: %d\n", ret); 136 return ret; 137 } 138 139 return 0; 140} 141 142static const struct component_ops imx8mp_hdmi_pai_ops = { 143 .bind = imx8mp_hdmi_pai_bind, 144}; 145 146static int imx8mp_hdmi_pai_probe(struct platform_device *pdev) 147{ 148 return component_add(&pdev->dev, &imx8mp_hdmi_pai_ops); 149} 150 151static void imx8mp_hdmi_pai_remove(struct platform_device *pdev) 152{ 153 component_del(&pdev->dev, &imx8mp_hdmi_pai_ops); 154} 155 156static const struct of_device_id imx8mp_hdmi_pai_of_table[] = { 157 { .compatible = "fsl,imx8mp-hdmi-pai" }, 158 { /* Sentinel */ } 159}; 160MODULE_DEVICE_TABLE(of, imx8mp_hdmi_pai_of_table); 161 162static struct platform_driver imx8mp_hdmi_pai_platform_driver = { 163 .probe = imx8mp_hdmi_pai_probe, 164 .remove = imx8mp_hdmi_pai_remove, 165 .driver = { 166 .name = "imx8mp-hdmi-pai", 167 .of_match_table = imx8mp_hdmi_pai_of_table, 168 }, 169}; 170module_platform_driver(imx8mp_hdmi_pai_platform_driver); 171 172MODULE_DESCRIPTION("i.MX8MP HDMI PAI driver"); 173MODULE_LICENSE("GPL");
~/
Read-only file preview.