Skip to content

Commit

Permalink
add gf hdaudio 001 patch in deepin kernel 6.6
Browse files Browse the repository at this point in the history
Signed-off-by: jasontao <[email protected]>
Change-Id: Ief9a58e29ec73540da4d05e0fa79bf75e0f0da6f
  • Loading branch information
jasontao authored and Siyuli committed Dec 3, 2024
1 parent d4f823f commit 9135c3a
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 3 deletions.
108 changes: 107 additions & 1 deletion sound/pci/hda/hda_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>

#include <linux/pci.h>
#include "hda_phytium.h"

#ifdef CONFIG_X86
Expand All @@ -27,6 +27,7 @@
#include <sound/core.h>
#include <sound/initval.h>
#include "hda_controller.h"
#include "hda_intel.h"
#include "hda_local.h"

#define CREATE_TRACE_POINTS
Expand Down Expand Up @@ -82,6 +83,104 @@ static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream,
return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0;
}

int gf_setup_bdle(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
__le32 *bdl;
unsigned int i, stream_idx;
struct gf_private *gf_chip = NULL;

// setup BDL and BDLE
if ((chip->pci != NULL) && (chip->pci->vendor == 0x6766) && (chip->pci->device == 0x3d40)) {
gf_chip = container_of(chip, struct gf_private, hda.chip);
if (gf_chip == NULL) {
return -1;
}
stream_idx = apcm->codec->addr - 1;
if ((stream_idx <= 1) && (gf_chip->diu_fb_bdl_vaddr[stream_idx])) {
if (azx_dev->core.bdl.bytes <= BDL_SIZE) {
memcpy(gf_chip->diu_fb_bdl_vaddr[stream_idx], azx_dev->core.bdl.area, azx_dev->core.bdl.bytes);
} else {
memcpy(gf_chip->diu_fb_bdl_vaddr[stream_idx], azx_dev->core.bdl.area, BDL_SIZE);
}
bdl = (__le32 *)gf_chip->diu_fb_bdl_vaddr[stream_idx];
for (i = 0; i < azx_dev->core.frags; i++) {
if (i > 0) {
bdl[i*4] = cpu_to_le32((u32)(bdl[(i-1)*4] + bdl[(i-1)*4+2]));
bdl[i*4+1] = cpu_to_le32(upper_32_bits(gf_chip->diu_fb_stream_ofs[stream_idx]));
}
else {
bdl[i*4] = cpu_to_le32((u32)gf_chip->diu_fb_stream_ofs[stream_idx]);
bdl[i*4+1] = cpu_to_le32(upper_32_bits(gf_chip->diu_fb_stream_ofs[stream_idx]));
}
}
snd_hdac_stream_writel((azx_stream(azx_dev)), SD_BDLPL, (u32)gf_chip->diu_fb_bdl_ofs[stream_idx]);
snd_hdac_stream_writel((azx_stream(azx_dev)), SD_BDLPU, upper_32_bits(gf_chip->diu_fb_bdl_ofs[stream_idx]));
}
}
return 0;
}

int gf_pre_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
unsigned int stream_idx;
struct gf_private *gf_chip = NULL;

if ((substream->runtime) && (chip->pci != NULL) && (chip->pci->vendor == 0x6766) && (chip->pci->device == 0x3d40)) {
gf_chip = container_of(chip, struct gf_private, hda.chip);
if (gf_chip == NULL) {
return -1;
}
stream_idx = apcm->codec->addr - 1;
if ((cmd == SNDRV_PCM_TRIGGER_START) &&
(stream_idx <= 1) && (gf_chip->diu_fb_stream_vaddr[stream_idx]) && (substream->runtime->dma_area)) {
memcpy(gf_chip->diu_fb_stream_vaddr[stream_idx], substream->runtime->dma_area, substream->runtime->dma_bytes);
gf_chip->diu_fb_stream_pos[stream_idx] = 0;
}
}
return 0;
}

int gf_update_stream(struct snd_pcm_substream *substream)
{
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
unsigned int stream_idx, hw_pos, appl_pos;
struct gf_private *gf_chip = NULL;

if ((substream->runtime) && (chip->pci != NULL) && (chip->pci->vendor == 0x6766) && (chip->pci->device == 0x3d40)) {
gf_chip = container_of(chip, struct gf_private, hda.chip);
if (gf_chip == NULL) {
return -1;
}
stream_idx = apcm->codec->addr - 1;
if ((stream_idx <= 1) && (gf_chip->diu_fb_stream_vaddr[stream_idx]) && (substream->runtime->dma_area) &&
(substream->runtime->dma_bytes <= GF_HDA_FB_STREAM_SIZE) && snd_pcm_running(substream)) {
hw_pos = frames_to_bytes(substream->runtime, substream->runtime->status->hw_ptr % substream->runtime->buffer_size);
appl_pos = frames_to_bytes(substream->runtime, substream->runtime->control->appl_ptr % substream->runtime->buffer_size);

if (hw_pos == appl_pos) {
memcpy(gf_chip->diu_fb_stream_vaddr[stream_idx], substream->runtime->dma_area, substream->runtime->dma_bytes);
}
else if (appl_pos > gf_chip->diu_fb_stream_pos[stream_idx]) {
memcpy(gf_chip->diu_fb_stream_vaddr[stream_idx] + gf_chip->diu_fb_stream_pos[stream_idx], substream->runtime->dma_area + gf_chip->diu_fb_stream_pos[stream_idx], (appl_pos - gf_chip->diu_fb_stream_pos[stream_idx]));
}
else if (appl_pos < gf_chip->diu_fb_stream_pos[stream_idx]) {
if(substream->runtime->dma_bytes > gf_chip->diu_fb_stream_pos[stream_idx]) {
memcpy(gf_chip->diu_fb_stream_vaddr[stream_idx] + gf_chip->diu_fb_stream_pos[stream_idx], substream->runtime->dma_area + gf_chip->diu_fb_stream_pos[stream_idx], (substream->runtime->dma_bytes - gf_chip->diu_fb_stream_pos[stream_idx]));
}
memcpy(gf_chip->diu_fb_stream_vaddr[stream_idx], substream->runtime->dma_area, appl_pos);
}
gf_chip->diu_fb_stream_pos[stream_idx] = appl_pos;
}
}
return 0;
}

/*
* PCM ops
*/
Expand Down Expand Up @@ -189,6 +288,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)

snd_hdac_stream_setup(azx_stream(azx_dev));

gf_setup_bdle(substream);

stream_tag = azx_dev->core.stream_tag;
/* CA-IBG chips need the playback stream starting from 1 */
if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
Expand Down Expand Up @@ -243,6 +344,8 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return -EINVAL;
}

gf_pre_trigger(substream, cmd);

snd_pcm_group_for_each_entry(s, substream) {
if (s->pcm->card != substream->pcm->card)
continue;
Expand Down Expand Up @@ -330,6 +433,9 @@ static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);

gf_update_stream(substream);

return bytes_to_frames(substream->runtime,
azx_get_position(chip, azx_dev));
}
Expand Down
3 changes: 3 additions & 0 deletions sound/pci/hda/hda_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#define AZX_MAX_CODECS HDA_MAX_CODECS
#define AZX_DEFAULT_CODECS 4

#define GF_HDA_PATCH_VERSION 1
#define GF_HDA_FB_STREAM_SIZE 7*1024*1024

/* driver quirks (capabilities) */
/* bits 0-7 are used for indicating driver type */
#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */
Expand Down
92 changes: 90 additions & 2 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,83 @@ static void azx_free_pci_zx(struct azx *chip)
iounmap(chip->remap_diu_addr);
}

static int gf_init_pci(struct azx *chip)
{
struct pci_dev *diu_pci = NULL;
unsigned long fb_size;
phys_addr_t diu_fb_base;
phys_addr_t diu_fb_stream[2];
phys_addr_t diu_fb_bdl[2];
struct gf_private *gf_chip = NULL;

dev_info(chip->card->dev, "gf_hda patch version %03d \n", GF_HDA_PATCH_VERSION);

if ((chip->pci != NULL) && (chip->pci->vendor == 0x6766) && (chip->pci->device == 0x3d40)) {
gf_chip = container_of(chip, struct gf_private, hda.chip);
if (gf_chip == NULL) {
return -1;
}
gf_chip->diu_fb_stream_vaddr[0] = NULL;
gf_chip->diu_fb_stream_vaddr[1] = NULL;
gf_chip->diu_fb_bdl_vaddr[0] = NULL;
gf_chip->diu_fb_bdl_vaddr[1] = NULL;

if (chip->pci->bus != NULL)
diu_pci = pci_get_slot(chip->pci->bus, PCI_DEVFN(PCI_SLOT(chip->pci->devfn), 0));

if (!diu_pci) {
dev_info(chip->card->dev, "gf_hda can't get display device\n");
}
else {
diu_fb_base = pci_resource_start(diu_pci, 1);
fb_size = pci_resource_len(diu_pci, 1);

diu_fb_stream[0] = diu_fb_base + fb_size - (4+16)*1024*1024;
gf_chip->diu_fb_stream_ofs[0] = diu_fb_stream[0] - diu_fb_base; // stream offset = fb_size -4M-16M
gf_chip->diu_fb_stream_vaddr[0] = ioremap_wc(diu_fb_stream[0], GF_HDA_FB_STREAM_SIZE); // size = 7M

diu_fb_stream[1] = diu_fb_stream[0] + GF_HDA_FB_STREAM_SIZE;
gf_chip->diu_fb_stream_ofs[1] = diu_fb_stream[1] - diu_fb_base; // stream offset = fb_size -4M-16M+7M
gf_chip->diu_fb_stream_vaddr[1] = ioremap_wc(diu_fb_stream[1], GF_HDA_FB_STREAM_SIZE); // size = 7M

diu_fb_bdl[0] = diu_fb_stream[1] + GF_HDA_FB_STREAM_SIZE;
gf_chip->diu_fb_bdl_ofs[0] = diu_fb_bdl[0] - diu_fb_base; // stream offset = fb_size -4M-16M+7M*2
gf_chip->diu_fb_bdl_vaddr[0] = ioremap_wc(diu_fb_bdl[0], BDL_SIZE); // size = 4K

diu_fb_bdl[1] = diu_fb_bdl[0] + BDL_SIZE;
gf_chip->diu_fb_bdl_ofs[1] = diu_fb_bdl[1] - diu_fb_base; // stream offset = fb_size -4M-16M+7M*2+4K
gf_chip->diu_fb_bdl_vaddr[1] = ioremap_wc(diu_fb_bdl[1], BDL_SIZE); // size = 4K

dev_info(chip->card->dev, "gf_hda diu fb base=0x%llx, size=%dM.\n", diu_fb_base, (unsigned int)(fb_size >> 20));
}
}
return 0;
}

static void gf_free_pci(struct azx *chip)
{
struct gf_private *gf_chip = NULL;

if ((chip->pci != NULL) && (chip->pci->vendor == 0x6766) && (chip->pci->device == 0x3d40)) {
gf_chip = container_of(chip, struct gf_private, hda.chip);
if (gf_chip == NULL) {
return;
}

if(gf_chip->diu_fb_stream_vaddr[0])
iounmap(gf_chip->diu_fb_stream_vaddr[0]);

if(gf_chip->diu_fb_stream_vaddr[1])
iounmap(gf_chip->diu_fb_stream_vaddr[1]);

if(gf_chip->diu_fb_bdl_vaddr[0])
iounmap(gf_chip->diu_fb_bdl_vaddr[0]);

if(gf_chip->diu_fb_bdl_vaddr[1])
iounmap(gf_chip->diu_fb_bdl_vaddr[1]);
}
}

static void azx_init_pci(struct azx *chip)
{
int snoop_type = azx_get_snoop_type(chip);
Expand Down Expand Up @@ -1408,6 +1485,10 @@ static void azx_free(struct azx *chip)
if (bus->irq >= 0)
free_irq(bus->irq, (void*)chip);

if (chip->driver_type == AZX_DRIVER_GFHDMI) {
gf_free_pci(chip);
}

azx_free_stream_pages(chip);
azx_free_streams(chip);
snd_hdac_bus_exit(bus);
Expand Down Expand Up @@ -1816,7 +1897,12 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
if (err < 0)
return err;

hda = devm_kzalloc(&pci->dev, sizeof(*hda), GFP_KERNEL);
if ((pci != NULL) && (pci->vendor == 0x6766) && (pci->device == 0x3d40)) {
hda = devm_kzalloc(&pci->dev, sizeof(struct gf_private), GFP_KERNEL);
}
else {
hda = devm_kzalloc(&pci->dev, sizeof(*hda), GFP_KERNEL);
}
if (!hda)
return -ENOMEM;

Expand Down Expand Up @@ -1904,8 +1990,10 @@ static int azx_first_init(struct azx *chip)
* Fix response write request not synced to memory when handle
* hdac interrupt on Glenfly Gpus
*/
if (chip->driver_type == AZX_DRIVER_GFHDMI)
if (chip->driver_type == AZX_DRIVER_GFHDMI) {
bus->polling_mode = 1;
gf_init_pci(chip);
}

if (chip->driver_type == AZX_DRIVER_LOONGSON) {
bus->polling_mode = 1;
Expand Down
11 changes: 11 additions & 0 deletions sound/pci/hda/hda_intel.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,15 @@ struct hda_intel {
int probe_retry; /* being probe-retry */
};

struct gf_private {
struct hda_intel hda;

phys_addr_t diu_fb_stream_ofs[2];
void __iomem *diu_fb_stream_vaddr[2];
unsigned int diu_fb_stream_pos[2];

phys_addr_t diu_fb_bdl_ofs[2];
void __iomem *diu_fb_bdl_vaddr[2];
};

#endif
2 changes: 2 additions & 0 deletions sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -4622,6 +4622,8 @@ HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI", patch_nvhdmi_2ch),
HDA_CODEC_ENTRY(0x67663d80, "Arise 80 HDMI/DP", patch_gf_hdmi),
HDA_CODEC_ENTRY(0x67663d81, "Arise 81 HDMI/DP", patch_gf_hdmi),
HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP", patch_gf_hdmi),
HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP", patch_gf_hdmi),
HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP", patch_gf_hdmi),
Expand Down

0 comments on commit 9135c3a

Please sign in to comment.