Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 342649
b: refs/heads/master
c: 6e87bad
h: refs/heads/master
i:
  342647: c8a0efd
v: v3
  • Loading branch information
Mark Brown committed Oct 5, 2012
1 parent dfed50a commit ca6a23c
Show file tree
Hide file tree
Showing 3 changed files with 238 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e10f871190ce2f912317c874a56b9cc417e46e84
refs/heads/master: 6e87badd3f38e1a095d6e1b13828246c3e8486b5
194 changes: 194 additions & 0 deletions trunk/sound/soc/codecs/wm2200.c
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,192 @@ static int wm2200_dsp_load(struct snd_soc_codec *codec, int base)
return ret;
}

static int wm2200_setup_algs(struct snd_soc_codec *codec, int base)
{
struct regmap *regmap = codec->control_data;
struct wmfw_adsp1_id_hdr id;
struct wmfw_adsp1_alg_hdr *alg;
size_t algs;
int zm, dm, pm, ret, i;
__be32 val;

switch (base) {
case WM2200_DSP1_CONTROL_1:
dm = WM2200_DSP1_DM_BASE;
pm = WM2200_DSP1_PM_BASE;
zm = WM2200_DSP1_ZM_BASE;
break;
case WM2200_DSP2_CONTROL_1:
dm = WM2200_DSP2_DM_BASE;
pm = WM2200_DSP2_PM_BASE;
zm = WM2200_DSP2_ZM_BASE;
break;
default:
dev_err(codec->dev, "BASE %x\n", base);
BUG_ON(1);
return -EINVAL;
}

ret = regmap_raw_read(regmap, dm, &id, sizeof(id));
if (ret != 0) {
dev_err(codec->dev, "Failed to read algorithm info: %d\n",
ret);
return ret;
}

algs = be32_to_cpu(id.algs);
dev_info(codec->dev, "Firmware: %x v%d.%d.%d, %d algorithms\n",
be32_to_cpu(id.fw.id),
(be32_to_cpu(id.fw.ver) & 0xff000) >> 16,
(be32_to_cpu(id.fw.ver) & 0xff00) >> 8,
be32_to_cpu(id.fw.ver) & 0xff,
algs);

/* Read the terminator first to validate the length */
ret = regmap_raw_read(regmap, dm +
(sizeof(id) + (algs * sizeof(*alg))) / 2,
&val, sizeof(val));
if (ret != 0) {
dev_err(codec->dev, "Failed to read algorithm list end: %d\n",
ret);
return ret;
}

if (be32_to_cpu(val) != 0xbedead)
dev_warn(codec->dev, "Algorithm list end %x 0x%x != 0xbeadead\n",
(sizeof(id) + (algs * sizeof(*alg))) / 2,
be32_to_cpu(val));

alg = kzalloc(sizeof(*alg) * algs, GFP_KERNEL);
if (!alg)
return -ENOMEM;

ret = regmap_raw_read(regmap, dm + (sizeof(id) / 2),
alg, algs * sizeof(*alg));
if (ret != 0) {
dev_err(codec->dev, "Failed to read algorithm list: %d\n",
ret);
goto out;
}

for (i = 0; i < algs; i++) {
dev_info(codec->dev, "%d: ID %x v%d.%d.%d\n",
i, be32_to_cpu(alg[i].alg.id),
(be32_to_cpu(alg[i].alg.ver) & 0xff000) >> 16,
(be32_to_cpu(alg[i].alg.ver) & 0xff00) >> 8,
be32_to_cpu(alg[i].alg.ver) & 0xff);
}

out:
kfree(alg);
return ret;
}

static int wm2200_load_coeff(struct snd_soc_codec *codec, int base)
{
struct regmap *regmap = codec->control_data;
struct wmfw_coeff_hdr *hdr;
struct wmfw_coeff_item *blk;
const struct firmware *firmware;
const char *file, *region_name;
int ret, dm, pm, zm, pos, blocks, type, offset, reg;

switch (base) {
case WM2200_DSP1_CONTROL_1:
file = "wm2200-dsp1.bin";
dm = WM2200_DSP1_DM_BASE;
pm = WM2200_DSP1_PM_BASE;
zm = WM2200_DSP1_ZM_BASE;
break;
case WM2200_DSP2_CONTROL_1:
file = "wm2200-dsp2.bin";
dm = WM2200_DSP2_DM_BASE;
pm = WM2200_DSP2_PM_BASE;
zm = WM2200_DSP2_ZM_BASE;
break;
default:
dev_err(codec->dev, "BASE %x\n", base);
BUG_ON(1);
return -EINVAL;
}

ret = request_firmware(&firmware, file, codec->dev);
if (ret != 0) {
dev_err(codec->dev, "Failed to request '%s'\n", file);
return ret;
}

if (sizeof(*hdr) >= firmware->size) {
dev_err(codec->dev, "%s: file too short, %d bytes\n",
file, firmware->size);
return -EINVAL;
}

hdr = (void*)&firmware->data[0];
if (memcmp(hdr->magic, "WMDR", 4) != 0) {
dev_err(codec->dev, "%s: invalid magic\n", file);
return -EINVAL;
}

dev_dbg(codec->dev, "%s: v%d.%d.%d\n", file,
(le32_to_cpu(hdr->ver) >> 16) & 0xff,
(le32_to_cpu(hdr->ver) >> 8) & 0xff,
le32_to_cpu(hdr->ver) & 0xff);

pos = le32_to_cpu(hdr->len);

blocks = 0;
while (pos < firmware->size &&
pos - firmware->size > sizeof(*blk)) {
blk = (void*)(&firmware->data[pos]);

type = be32_to_cpu(blk->type) & 0xff;
offset = le32_to_cpu(blk->offset) & 0xffffff;

dev_dbg(codec->dev, "%s.%d: %x v%d.%d.%d\n",
file, blocks, le32_to_cpu(blk->id),
(le32_to_cpu(blk->ver) >> 16) & 0xff,
(le32_to_cpu(blk->ver) >> 8) & 0xff,
le32_to_cpu(blk->ver) & 0xff);
dev_dbg(codec->dev, "%s.%d: %d bytes at 0x%x in %x\n",
file, blocks, le32_to_cpu(blk->len), offset, type);

reg = 0;
region_name = "Unknown";
switch (type) {
case WMFW_NAME_TEXT:
case WMFW_INFO_TEXT:
break;
case WMFW_ABSOLUTE:
region_name = "register";
reg = offset;
break;
default:
dev_err(codec->dev, "Unknown region type %x\n", type);
break;
}

if (reg) {
ret = regmap_raw_write(regmap, reg, blk->data,
le32_to_cpu(blk->len));
if (ret != 0) {
dev_err(codec->dev,
"%s.%d: Failed to write to %x in %s\n",
file, blocks, reg, region_name);
}
}

pos += le32_to_cpu(blk->len) + sizeof(*blk);
blocks++;
}

if (pos > firmware->size)
dev_warn(codec->dev, "%s.%d: %d bytes at end of file\n",
file, blocks, pos - firmware->size);

return 0;
}

static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
Expand All @@ -1164,6 +1350,14 @@ static int wm2200_dsp_ev(struct snd_soc_dapm_widget *w,
if (ret != 0)
return ret;

ret = wm2200_setup_algs(codec, base);
if (ret != 0)
return ret;

ret = wm2200_load_coeff(codec, base);
if (ret != 0)
return ret;

/* Start the core running */
snd_soc_update_bits(codec, w->reg,
WM2200_DSP1_CORE_ENA | WM2200_DSP1_START,
Expand Down
43 changes: 43 additions & 0 deletions trunk/sound/soc/codecs/wmfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,49 @@ struct wmfw_region {
u8 data[];
} __packed;

struct wmfw_id_hdr {
__be32 core_id;
__be32 core_rev;
__be32 id;
__be32 ver;
} __packed;

struct wmfw_adsp1_id_hdr {
struct wmfw_id_hdr fw;
__be32 zm;
__be32 dm;
__be32 algs;
} __packed;

struct wmfw_alg_hdr {
__be32 id;
__be32 ver;
} __packed;

struct wmfw_adsp1_alg_hdr {
struct wmfw_alg_hdr alg;
__be32 zm;
__be32 dm;
} __packed;

struct wmfw_coeff_hdr {
u8 magic[4];
__le32 len;
__le32 ver;
u8 data[];
} __packed;

struct wmfw_coeff_item {
union {
__be32 type;
__le32 offset;
};
__le32 id;
__le32 ver;
__le32 sr;
__le32 len;
u8 data[];
} __packed;
#define WMFW_ADSP1 1

#define WMFW_ABSOLUTE 0xf0
Expand Down

0 comments on commit ca6a23c

Please sign in to comment.