Skip to content
Merged

Spi #107

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions arch/arm/boot/dts/bcm2836-rpi-2-b.dts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "bcm2835-rpi.dtsi"
#include "bcm283x-rpi-smsc9514.dtsi"
#include "bcm283x-rpi-usb-host.dtsi"
#include "bcm283x-rpi-sof.dtsi"

/ {
compatible = "raspberrypi,2-model-b", "brcm,bcm2836";
Expand Down
17 changes: 17 additions & 0 deletions arch/arm/boot/dts/bcm283x-rpi-sof.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// FIXME: which SPI bus is the card connected to?
@spi {
status = "okay";

sue-creek: sof-sue-creek@0 {
reg = <0>;
compatible = "sof,spi-sue-creek";
// FIXME: frequency value
spi-max-frequency = <54000000>;
fw_filename = "intel/sof-spi.ri";
tplg_filename = "intel/sof-spi.tplg";
// FIXME: GPIO controller and IRQ number and sense
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
irq-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
};
};
19 changes: 17 additions & 2 deletions include/sound/sof.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ enum sof_device_type {
/*
* SOF Platform data.
*/
struct snd_sof_machine {
const u8 id[ACPI_ID_LEN];
const char *drv_name;
const char *sof_fw_filename;
const char *sof_tplg_filename;
const char *asoc_plat_name;
const struct snd_sof_dsp_ops *ops;
};

struct snd_sof_pdata {
u32 id; /* PCI/ACPI ID */
const struct firmware *fw;
Expand All @@ -48,7 +57,10 @@ struct snd_sof_pdata {

/* machine */
struct platform_device *pdev_mach;
const struct snd_soc_acpi_mach *machine;
union {
const struct snd_soc_acpi_mach *machine;
const struct snd_sof_machine *sof_machine;
};
};

/*
Expand All @@ -57,7 +69,10 @@ struct snd_sof_pdata {
*/
struct sof_dev_desc {
/* list of machines using this configuration */
struct snd_soc_acpi_mach *machines;
union {
struct snd_soc_acpi_mach *machines;
struct snd_sof_machine *sof_machines;
};

/* Platform resource indexes in BAR / ACPI resources. */
/* Must set to -1 if not used - add new items to end */
Expand Down
3 changes: 3 additions & 0 deletions sound/soc/sof/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ config SND_SOC_SOF_PCI
config SND_SOC_SOF_ACPI
tristate

config SND_SOC_SOF_SPI
tristate

config SND_SOC_SOF
tristate "Sound Open Firmware Support"
select SND_SOC_TOPOLOGY
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev,
{
int i, pages;

pages = snd_sgbuf_aligned_pages(size);
pages = PAGE_ALIGN(size);

dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n",
dmab->area, size, pages);
Expand Down
134 changes: 92 additions & 42 deletions sound/soc/sof/hw-spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* Hardware interface for audio DSPs via SPI
*/

#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/slab.h>
Expand All @@ -29,22 +31,69 @@

#include "sof-priv.h"
#include "ops.h"
#include "intel.h"

/*
* Memory copy.
*/

static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src,
size_t size)
static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest,
size_t size)
{
// use spi_write() to copy data to DSP
u8 *buf;
int ret;

if (offset) {
buf = kmalloc(size + offset, GFP_KERNEL);
if (!buf) {
dev_err(sdev->dev, "Buffer allocation failed\n");
return;
}
} else {
buf = dest;
}

ret = spi_read(to_spi_device(sdev->dev), buf, size + offset);
if (ret < 0)
dev_err(sdev->dev, "SPI read failed: %d\n", ret);

if (offset) {
memcpy(dest, buf + offset, size);
kfree(buf);
}
}

static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest,
size_t size)
static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src,
size_t size)
{
// use spi_read() to copy data from DSP
int ret;
u8 *buf;

if (offset) {
buf = kmalloc(size + offset, GFP_KERNEL);
if (!buf) {
dev_err(sdev->dev, "Buffer allocation failed\n");
return;
}

/* Use Read-Modify-Wwrite */
ret = spi_read(to_spi_device(sdev->dev), buf, size + offset);
if (ret < 0) {
dev_err(sdev->dev, "SPI read failed: %d\n", ret);
goto free;
}

memcpy(buf + offset, src, size);
} else {
buf = src;
}

ret = spi_write(to_spi_device(sdev->dev), buf, size + offset);
if (ret < 0)
dev_err(sdev->dev, "SPI write failed: %d\n", ret);

free:
if (offset)
kfree(buf);
}

/*
Expand All @@ -59,7 +108,7 @@ static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)

// read local buffer with SPI data

dev_info(sdev->dev, " Firmware info: version %d:%d-%s build %d on %s:%s\n",
dev_info(sdev->dev, "Firmware info: version %d:%d-%s build %d on %s:%s\n",
v->major, v->minor, v->tag, v->build, v->date, v->time);

return 0;
Expand All @@ -69,26 +118,25 @@ static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id)
* IPC Mailbox IO
*/

static void spi_mailbox_write(struct snd_sof_dev *sdev, u32 offset,
void *message, size_t bytes)
static void spi_mailbox_write(struct snd_sof_dev *sdev __maybe_unused,
u32 offset __maybe_unused,
void *message __maybe_unused,
size_t bytes __maybe_unused)
{
void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset;

//memcpy_toio(dest, message, bytes);
/*
* this will copy to a local memory buffer that will be sent to DSP via
* SPI at next IPC
*/
}

static void spi_mailbox_read(struct snd_sof_dev *sdev, u32 offset,
static void spi_mailbox_read(struct snd_sof_dev *sdev __maybe_unused,
u32 offset __maybe_unused,
void *message, size_t bytes)
{
void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset;
memset(message, 0, bytes);

//memcpy_fromio(message, src, bytes);
/*
* this will copy from a local memory buffer that will be received from
* this will copy from a local memory buffer that was received from
* DSP via SPI at last IPC
*/
}
Expand All @@ -97,9 +145,8 @@ static void spi_mailbox_read(struct snd_sof_dev *sdev, u32 offset,
* IPC Doorbell IRQ handler and thread.
*/

static irqreturn_t spi_irq_handler(int irq, void *context)
static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context __maybe_unused)
{
struct snd_sof_dev *sdev = (struct snd_sof_dev *)context;
int ret = IRQ_NONE;

// on SPI based devices this will likely come via a SoC GPIO IRQ
Expand All @@ -109,25 +156,21 @@ static irqreturn_t spi_irq_handler(int irq, void *context)
return ret;
}

static irqreturn_t spi_irq_thread(int irq, void *context)
static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_unused)
{
struct snd_sof_dev *sdev = (struct snd_sof_dev *)context;

// read SPI data into local buffer and determine IPC cmd or reply

/*
* if reply. Handle Immediate reply from DSP Core and set DSP
* state to ready
*/
//snd_sof_ipc_reply(sdev, ipcx);

/* if cmd, Handle messages from DSP Core */
//snd_sof_ipc_msgs_rx(sdev);

return IRQ_HANDLED;
}

static int spi_is_ready(struct snd_sof_dev *sdev)
static int spi_is_ready(struct snd_sof_dev *sdev __maybe_unused)
{
// use local variable to store DSP command state. either DSP is ready
// for new cmd or still processing current cmd.
Expand All @@ -137,8 +180,6 @@ static int spi_is_ready(struct snd_sof_dev *sdev)

static int spi_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
u64 cmd = msg->header;

/* send the message */
spi_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
msg->msg_size);
Expand All @@ -160,7 +201,7 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
} else {
/* reply correct size ? */
if (reply.hdr.size != msg->reply_size) {
dev_err(sdev->dev, "error: reply expected 0x%lx got 0x%x bytes\n",
dev_err(sdev->dev, "error: reply expected 0x%zu got 0x%x bytes\n",
msg->reply_size, reply.hdr.size);
size = msg->reply_size;
ret = -EINVAL;
Expand All @@ -183,22 +224,26 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)

static int spi_sof_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct sof_dev_desc *desc = pdata->desc;
struct platform_device *pdev =
container_of(sdev->parent, struct platform_device, dev);
int ret = 0;

/* get IRQ from Device tree or ACPI - register our IRQ */
struct irq_data *irqd;
struct spi_device *spi = to_spi_device(pdev->dev.parent);
int ret;

sdev->ipc_irq = spi->irq;
dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq);
ret = request_threaded_irq(sdev->ipc_irq, spi_irq_handler,
spi_irq_thread, IRQF_SHARED, "AudioDSP",
sdev);
if (ret < 0) {
irqd = irq_get_irq_data(sdev->ipc_irq);
if (!irqd)
return -EINVAL;

ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq,
spi_irq_handler, spi_irq_thread,
irqd_get_trigger_type(irqd) | IRQF_ONESHOT,
"AudioDSP", sdev);
if (ret < 0)
dev_err(sdev->dev, "error: failed to register IRQ %d\n",
sdev->ipc_irq);
goto irq_err;
}

return ret;
}
Expand All @@ -209,7 +254,12 @@ static int spi_sof_remove(struct snd_sof_dev *sdev)
return 0;
}

/* baytrail ops */
static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __maybe_unused)
{
return 0;
}

/* SPI SOF ops */
struct snd_sof_dsp_ops snd_sof_spi_ops = {
/* device init */
.probe = spi_sof_probe,
Expand All @@ -235,9 +285,9 @@ struct snd_sof_dsp_ops snd_sof_spi_ops = {
.cmd_done = spi_cmd_done,

/* debug */
.debug_map = spi_debugfs,
.debug_map_count = ARRAY_SIZE(spi_debugfs),
.dbg_dump = spi_dump,
.debug_map = NULL/*spi_debugfs*/,
.debug_map_count = 0/*ARRAY_SIZE(spi_debugfs)*/,
.dbg_dump = NULL/*spi_dump*/,

/* module loading */
.load_module = snd_sof_parse_module_memcpy,
Expand Down
11 changes: 11 additions & 0 deletions sound/soc/sof/intel/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ config SND_SOC_SOF_INTEL
Say Y if you have such a device.
If unsure select "N".

config SND_SOC_SOF_SPIDSP
tristate "SOF support over the SPI bus"
depends on SND_SOC_SOF
depends on SPI
select SND_SOC_SOF_SPI
help
This adds support for Sound Open Firmware over SPI for Device
Tree based systems.
Say Y if you have such a device.
If unsure select "N".

if SND_SOC_SOF_INTEL

config SND_SOC_SOF_BAYTRAIL
Expand Down
12 changes: 10 additions & 2 deletions sound/soc/sof/intel/hda-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,20 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, int tag)
int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot)
{
struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev);
const char *fw_filename;

/* set code loading condition to true */
sdev->code_loading = 1;

return request_firmware(&plat_data->fw,
plat_data->machine->sof_fw_filename, sdev->dev);
switch (plat_data->type) {
case SOF_DEVICE_SPI:
fw_filename = plat_data->sof_machine->sof_fw_filename;
break;
default:
fw_filename = plat_data->machine->sof_fw_filename;
}

return request_firmware(&plat_data->fw, fw_filename, sdev->dev);
}

int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
Expand Down
Loading