Skip to content

Commit

Permalink
ASoC: Intel: Add catpt base members
Browse files Browse the repository at this point in the history
Declare base structures, registers and extension routines for the catpt
solution.

Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20200929141247.8058-2-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Cezary Rojewski authored and Mark Brown committed Oct 2, 2020
1 parent 8f2242b commit 4fac9b3
Show file tree
Hide file tree
Showing 4 changed files with 449 additions and 0 deletions.
86 changes: 86 additions & 0 deletions sound/soc/intel/catpt/core.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2020 Intel Corporation. All rights reserved.
*
* Author: Cezary Rojewski <cezary.rojewski@intel.com>
*/

#ifndef __SND_SOC_INTEL_CATPT_CORE_H
#define __SND_SOC_INTEL_CATPT_CORE_H

#include <linux/dma/dw.h>
#include "registers.h"

struct catpt_dev;

void catpt_sram_init(struct resource *sram, u32 start, u32 size);
void catpt_sram_free(struct resource *sram);
struct resource *
catpt_request_region(struct resource *root, resource_size_t size);

static inline bool catpt_resource_overlapping(struct resource *r1,
struct resource *r2,
struct resource *ret)
{
if (!resource_overlaps(r1, r2))
return false;
ret->start = max(r1->start, r2->start);
ret->end = min(r1->end, r2->end);
return true;
}

struct catpt_module_type {
bool loaded;
u32 entry_point;
u32 persistent_size;
u32 scratch_size;
/* DRAM, initial module state */
u32 state_offset;
u32 state_size;

struct list_head node;
};

struct catpt_spec {
struct snd_soc_acpi_mach *machines;
u8 core_id;
u32 host_dram_offset;
u32 host_iram_offset;
u32 host_shim_offset;
u32 host_dma_offset[CATPT_DMA_COUNT];
u32 host_ssp_offset[CATPT_SSP_COUNT];
u32 dram_mask;
u32 iram_mask;
void (*pll_shutdown)(struct catpt_dev *cdev, bool enable);
int (*power_up)(struct catpt_dev *cdev);
int (*power_down)(struct catpt_dev *cdev);
};

struct catpt_dev {
struct device *dev;
struct dw_dma_chip *dmac;

void __iomem *pci_ba;
void __iomem *lpe_ba;
u32 lpe_base;
int irq;

const struct catpt_spec *spec;
struct completion fw_ready;

struct resource dram;
struct resource iram;
struct resource *scratch;
};

int catpt_dmac_probe(struct catpt_dev *cdev);
void catpt_dmac_remove(struct catpt_dev *cdev);
struct dma_chan *catpt_dma_request_config_chan(struct catpt_dev *cdev);
int catpt_dma_memcpy_todsp(struct catpt_dev *cdev, struct dma_chan *chan,
dma_addr_t dst_addr, dma_addr_t src_addr,
size_t size);
int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
dma_addr_t dst_addr, dma_addr_t src_addr,
size_t size);

#endif
138 changes: 138 additions & 0 deletions sound/soc/intel/catpt/dsp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2020 Intel Corporation. All rights reserved.
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//

#include <linux/dma-mapping.h>
#include <linux/firmware.h>
#include "core.h"
#include "registers.h"

static bool catpt_dma_filter(struct dma_chan *chan, void *param)
{
return param == chan->device->dev;
}

/*
* Either engine 0 or 1 can be used for image loading.
* Align with Windows driver equivalent and stick to engine 1.
*/
#define CATPT_DMA_DEVID 1
#define CATPT_DMA_DSP_ADDR_MASK GENMASK(31, 20)

struct dma_chan *catpt_dma_request_config_chan(struct catpt_dev *cdev)
{
struct dma_slave_config config;
struct dma_chan *chan;
dma_cap_mask_t mask;
int ret;

dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);

chan = dma_request_channel(mask, catpt_dma_filter, cdev->dev);
if (!chan) {
dev_err(cdev->dev, "request channel failed\n");
return ERR_PTR(-ENODEV);
}

memset(&config, 0, sizeof(config));
config.direction = DMA_MEM_TO_DEV;
config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
config.src_maxburst = 16;
config.dst_maxburst = 16;

ret = dmaengine_slave_config(chan, &config);
if (ret) {
dev_err(cdev->dev, "slave config failed: %d\n", ret);
dma_release_channel(chan);
return ERR_PTR(ret);
}

return chan;
}

static int catpt_dma_memcpy(struct catpt_dev *cdev, struct dma_chan *chan,
dma_addr_t dst_addr, dma_addr_t src_addr,
size_t size)
{
struct dma_async_tx_descriptor *desc;
enum dma_status status;

desc = dmaengine_prep_dma_memcpy(chan, dst_addr, src_addr, size,
DMA_CTRL_ACK);
if (!desc) {
dev_err(cdev->dev, "prep dma memcpy failed\n");
return -EIO;
}

/* enable demand mode for dma channel */
catpt_updatel_shim(cdev, HMDC,
CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id),
CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id));
dmaengine_submit(desc);
status = dma_wait_for_async_tx(desc);
/* regardless of status, disable access to HOST memory in demand mode */
catpt_updatel_shim(cdev, HMDC,
CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);

return (status == DMA_COMPLETE) ? 0 : -EPROTO;
}

int catpt_dma_memcpy_todsp(struct catpt_dev *cdev, struct dma_chan *chan,
dma_addr_t dst_addr, dma_addr_t src_addr,
size_t size)
{
return catpt_dma_memcpy(cdev, chan, dst_addr | CATPT_DMA_DSP_ADDR_MASK,
src_addr, size);
}

int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
dma_addr_t dst_addr, dma_addr_t src_addr,
size_t size)
{
return catpt_dma_memcpy(cdev, chan, dst_addr,
src_addr | CATPT_DMA_DSP_ADDR_MASK, size);
}

int catpt_dmac_probe(struct catpt_dev *cdev)
{
struct dw_dma_chip *dmac;
int ret;

dmac = devm_kzalloc(cdev->dev, sizeof(*dmac), GFP_KERNEL);
if (!dmac)
return -ENOMEM;

dmac->regs = cdev->lpe_ba + cdev->spec->host_dma_offset[CATPT_DMA_DEVID];
dmac->dev = cdev->dev;
dmac->irq = cdev->irq;

ret = dma_coerce_mask_and_coherent(cdev->dev, DMA_BIT_MASK(31));
if (ret)
return ret;
/*
* Caller is responsible for putting device in D0 to allow
* for I/O and memory access before probing DW.
*/
ret = dw_dma_probe(dmac);
if (ret)
return ret;

cdev->dmac = dmac;
return 0;
}

void catpt_dmac_remove(struct catpt_dev *cdev)
{
/*
* As do_dma_remove() juggles with pm_runtime_get_xxx() and
* pm_runtime_put_xxx() while both ADSP and DW 'devices' are part of
* the same module, caller makes sure pm_runtime_disable() is invoked
* before removing DW to prevent postmortem resume and suspend.
*/
dw_dma_remove(cdev->dmac);
}
46 changes: 46 additions & 0 deletions sound/soc/intel/catpt/loader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright(c) 2020 Intel Corporation. All rights reserved.
//
// Author: Cezary Rojewski <cezary.rojewski@intel.com>
//

#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include "core.h"

void catpt_sram_init(struct resource *sram, u32 start, u32 size)
{
sram->start = start;
sram->end = start + size - 1;
}

void catpt_sram_free(struct resource *sram)
{
struct resource *res, *save;

for (res = sram->child; res;) {
save = res->sibling;
release_resource(res);
kfree(res);
res = save;
}
}

struct resource *
catpt_request_region(struct resource *root, resource_size_t size)
{
struct resource *res = root->child;
resource_size_t addr = root->start;

for (;;) {
if (res->start - addr >= size)
break;
addr = res->end + 1;
res = res->sibling;
if (!res)
return NULL;
}

return __request_region(root, addr, size, NULL, 0);
}
Loading

0 comments on commit 4fac9b3

Please sign in to comment.