0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/devcoredump.h>
0009 #include <linux/dma-mapping.h>
0010 #include <linux/firmware.h>
0011 #include <linux/pci.h>
0012 #include <linux/pxa2xx_ssp.h>
0013 #include "core.h"
0014 #include "messages.h"
0015 #include "registers.h"
0016
0017 static bool catpt_dma_filter(struct dma_chan *chan, void *param)
0018 {
0019 return param == chan->device->dev;
0020 }
0021
0022
0023
0024
0025
0026 #define CATPT_DMA_DEVID 1
0027 #define CATPT_DMA_DSP_ADDR_MASK GENMASK(31, 20)
0028
0029 struct dma_chan *catpt_dma_request_config_chan(struct catpt_dev *cdev)
0030 {
0031 struct dma_slave_config config;
0032 struct dma_chan *chan;
0033 dma_cap_mask_t mask;
0034 int ret;
0035
0036 dma_cap_zero(mask);
0037 dma_cap_set(DMA_MEMCPY, mask);
0038
0039 chan = dma_request_channel(mask, catpt_dma_filter, cdev->dev);
0040 if (!chan) {
0041 dev_err(cdev->dev, "request channel failed\n");
0042 return ERR_PTR(-ENODEV);
0043 }
0044
0045 memset(&config, 0, sizeof(config));
0046 config.direction = DMA_MEM_TO_DEV;
0047 config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0048 config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0049 config.src_maxburst = 16;
0050 config.dst_maxburst = 16;
0051
0052 ret = dmaengine_slave_config(chan, &config);
0053 if (ret) {
0054 dev_err(cdev->dev, "slave config failed: %d\n", ret);
0055 dma_release_channel(chan);
0056 return ERR_PTR(ret);
0057 }
0058
0059 return chan;
0060 }
0061
0062 static int catpt_dma_memcpy(struct catpt_dev *cdev, struct dma_chan *chan,
0063 dma_addr_t dst_addr, dma_addr_t src_addr,
0064 size_t size)
0065 {
0066 struct dma_async_tx_descriptor *desc;
0067 enum dma_status status;
0068 int ret;
0069
0070 desc = dmaengine_prep_dma_memcpy(chan, dst_addr, src_addr, size,
0071 DMA_CTRL_ACK);
0072 if (!desc) {
0073 dev_err(cdev->dev, "prep dma memcpy failed\n");
0074 return -EIO;
0075 }
0076
0077
0078 catpt_updatel_shim(cdev, HMDC,
0079 CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id),
0080 CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id));
0081
0082 ret = dma_submit_error(dmaengine_submit(desc));
0083 if (ret) {
0084 dev_err(cdev->dev, "submit tx failed: %d\n", ret);
0085 goto clear_hdda;
0086 }
0087
0088 status = dma_wait_for_async_tx(desc);
0089 ret = (status == DMA_COMPLETE) ? 0 : -EPROTO;
0090
0091 clear_hdda:
0092
0093 catpt_updatel_shim(cdev, HMDC,
0094 CATPT_HMDC_HDDA(CATPT_DMA_DEVID, chan->chan_id), 0);
0095
0096 return ret;
0097 }
0098
0099 int catpt_dma_memcpy_todsp(struct catpt_dev *cdev, struct dma_chan *chan,
0100 dma_addr_t dst_addr, dma_addr_t src_addr,
0101 size_t size)
0102 {
0103 return catpt_dma_memcpy(cdev, chan, dst_addr | CATPT_DMA_DSP_ADDR_MASK,
0104 src_addr, size);
0105 }
0106
0107 int catpt_dma_memcpy_fromdsp(struct catpt_dev *cdev, struct dma_chan *chan,
0108 dma_addr_t dst_addr, dma_addr_t src_addr,
0109 size_t size)
0110 {
0111 return catpt_dma_memcpy(cdev, chan, dst_addr,
0112 src_addr | CATPT_DMA_DSP_ADDR_MASK, size);
0113 }
0114
0115 int catpt_dmac_probe(struct catpt_dev *cdev)
0116 {
0117 struct dw_dma_chip *dmac;
0118 int ret;
0119
0120 dmac = devm_kzalloc(cdev->dev, sizeof(*dmac), GFP_KERNEL);
0121 if (!dmac)
0122 return -ENOMEM;
0123
0124 dmac->regs = cdev->lpe_ba + cdev->spec->host_dma_offset[CATPT_DMA_DEVID];
0125 dmac->dev = cdev->dev;
0126 dmac->irq = cdev->irq;
0127
0128 ret = dma_coerce_mask_and_coherent(cdev->dev, DMA_BIT_MASK(31));
0129 if (ret)
0130 return ret;
0131
0132
0133
0134
0135 ret = dw_dma_probe(dmac);
0136 if (ret)
0137 return ret;
0138
0139 cdev->dmac = dmac;
0140 return 0;
0141 }
0142
0143 void catpt_dmac_remove(struct catpt_dev *cdev)
0144 {
0145
0146
0147
0148
0149
0150
0151 dw_dma_remove(cdev->dmac);
0152 }
0153
0154 static void catpt_dsp_set_srampge(struct catpt_dev *cdev, struct resource *sram,
0155 unsigned long mask, unsigned long new)
0156 {
0157 unsigned long old;
0158 u32 off = sram->start;
0159 u32 b = __ffs(mask);
0160
0161 old = catpt_readl_pci(cdev, VDRTCTL0) & mask;
0162 dev_dbg(cdev->dev, "SRAMPGE [0x%08lx] 0x%08lx -> 0x%08lx",
0163 mask, old, new);
0164
0165 if (old == new)
0166 return;
0167
0168 catpt_updatel_pci(cdev, VDRTCTL0, mask, new);
0169
0170 udelay(60);
0171
0172
0173
0174
0175
0176 for_each_clear_bit_from(b, &new, fls_long(mask)) {
0177 u8 buf[4];
0178
0179
0180 if (test_bit(b, &old)) {
0181 dev_dbg(cdev->dev, "sanitize block %ld: off 0x%08x\n",
0182 b - __ffs(mask), off);
0183 memcpy_fromio(buf, cdev->lpe_ba + off, sizeof(buf));
0184 }
0185 off += CATPT_MEMBLOCK_SIZE;
0186 }
0187 }
0188
0189 void catpt_dsp_update_srampge(struct catpt_dev *cdev, struct resource *sram,
0190 unsigned long mask)
0191 {
0192 struct resource *res;
0193 unsigned long new = 0;
0194
0195
0196 for (res = sram->child; res; res = res->sibling) {
0197 u32 h, l;
0198
0199 h = (res->end - sram->start) / CATPT_MEMBLOCK_SIZE;
0200 l = (res->start - sram->start) / CATPT_MEMBLOCK_SIZE;
0201 new |= GENMASK(h, l);
0202 }
0203
0204
0205 new = ~(new << __ffs(mask)) & mask;
0206
0207
0208 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE, 0);
0209
0210 catpt_dsp_set_srampge(cdev, sram, mask, new);
0211
0212
0213 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE,
0214 CATPT_VDRTCTL2_DCLCGE);
0215 }
0216
0217 int catpt_dsp_stall(struct catpt_dev *cdev, bool stall)
0218 {
0219 u32 reg, val;
0220
0221 val = stall ? CATPT_CS_STALL : 0;
0222 catpt_updatel_shim(cdev, CS1, CATPT_CS_STALL, val);
0223
0224 return catpt_readl_poll_shim(cdev, CS1,
0225 reg, (reg & CATPT_CS_STALL) == val,
0226 500, 10000);
0227 }
0228
0229 static int catpt_dsp_reset(struct catpt_dev *cdev, bool reset)
0230 {
0231 u32 reg, val;
0232
0233 val = reset ? CATPT_CS_RST : 0;
0234 catpt_updatel_shim(cdev, CS1, CATPT_CS_RST, val);
0235
0236 return catpt_readl_poll_shim(cdev, CS1,
0237 reg, (reg & CATPT_CS_RST) == val,
0238 500, 10000);
0239 }
0240
0241 void lpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable)
0242 {
0243 u32 val;
0244
0245 val = enable ? LPT_VDRTCTL0_APLLSE : 0;
0246 catpt_updatel_pci(cdev, VDRTCTL0, LPT_VDRTCTL0_APLLSE, val);
0247 }
0248
0249 void wpt_dsp_pll_shutdown(struct catpt_dev *cdev, bool enable)
0250 {
0251 u32 val;
0252
0253 val = enable ? WPT_VDRTCTL2_APLLSE : 0;
0254 catpt_updatel_pci(cdev, VDRTCTL2, WPT_VDRTCTL2_APLLSE, val);
0255 }
0256
0257 static int catpt_dsp_select_lpclock(struct catpt_dev *cdev, bool lp, bool waiti)
0258 {
0259 u32 mask, reg, val;
0260 int ret;
0261
0262 mutex_lock(&cdev->clk_mutex);
0263
0264 val = lp ? CATPT_CS_LPCS : 0;
0265 reg = catpt_readl_shim(cdev, CS1) & CATPT_CS_LPCS;
0266 dev_dbg(cdev->dev, "LPCS [0x%08lx] 0x%08x -> 0x%08x",
0267 CATPT_CS_LPCS, reg, val);
0268
0269 if (reg == val) {
0270 mutex_unlock(&cdev->clk_mutex);
0271 return 0;
0272 }
0273
0274 if (waiti) {
0275
0276 ret = catpt_readl_poll_shim(cdev, ISD,
0277 reg, (reg & CATPT_ISD_DCPWM),
0278 500, 10000);
0279 if (ret) {
0280 dev_warn(cdev->dev, "await WAITI timeout\n");
0281
0282 if (lp) {
0283 mutex_unlock(&cdev->clk_mutex);
0284 return 0;
0285 }
0286 }
0287 }
0288
0289 ret = catpt_readl_poll_shim(cdev, CLKCTL,
0290 reg, !(reg & CATPT_CLKCTL_CFCIP),
0291 500, 10000);
0292 if (ret)
0293 dev_warn(cdev->dev, "clock change still in progress\n");
0294
0295
0296 val |= CATPT_CS_DCS_HIGH;
0297 mask = CATPT_CS_LPCS | CATPT_CS_DCS;
0298 catpt_updatel_shim(cdev, CS1, mask, val);
0299
0300 ret = catpt_readl_poll_shim(cdev, CLKCTL,
0301 reg, !(reg & CATPT_CLKCTL_CFCIP),
0302 500, 10000);
0303 if (ret)
0304 dev_warn(cdev->dev, "clock change still in progress\n");
0305
0306
0307 cdev->spec->pll_shutdown(cdev, lp);
0308
0309 mutex_unlock(&cdev->clk_mutex);
0310 return 0;
0311 }
0312
0313 int catpt_dsp_update_lpclock(struct catpt_dev *cdev)
0314 {
0315 struct catpt_stream_runtime *stream;
0316
0317 list_for_each_entry(stream, &cdev->stream_list, node)
0318 if (stream->prepared)
0319 return catpt_dsp_select_lpclock(cdev, false, true);
0320
0321 return catpt_dsp_select_lpclock(cdev, true, true);
0322 }
0323
0324
0325 static void catpt_dsp_set_regs_defaults(struct catpt_dev *cdev)
0326 {
0327 int i;
0328
0329 catpt_writel_shim(cdev, CS1, CATPT_CS_DEFAULT);
0330 catpt_writel_shim(cdev, ISC, CATPT_ISC_DEFAULT);
0331 catpt_writel_shim(cdev, ISD, CATPT_ISD_DEFAULT);
0332 catpt_writel_shim(cdev, IMC, CATPT_IMC_DEFAULT);
0333 catpt_writel_shim(cdev, IMD, CATPT_IMD_DEFAULT);
0334 catpt_writel_shim(cdev, IPCC, CATPT_IPCC_DEFAULT);
0335 catpt_writel_shim(cdev, IPCD, CATPT_IPCD_DEFAULT);
0336 catpt_writel_shim(cdev, CLKCTL, CATPT_CLKCTL_DEFAULT);
0337 catpt_writel_shim(cdev, CS2, CATPT_CS2_DEFAULT);
0338 catpt_writel_shim(cdev, LTRC, CATPT_LTRC_DEFAULT);
0339 catpt_writel_shim(cdev, HMDC, CATPT_HMDC_DEFAULT);
0340
0341 for (i = 0; i < CATPT_SSP_COUNT; i++) {
0342 catpt_writel_ssp(cdev, i, SSCR0, CATPT_SSC0_DEFAULT);
0343 catpt_writel_ssp(cdev, i, SSCR1, CATPT_SSC1_DEFAULT);
0344 catpt_writel_ssp(cdev, i, SSSR, CATPT_SSS_DEFAULT);
0345 catpt_writel_ssp(cdev, i, SSITR, CATPT_SSIT_DEFAULT);
0346 catpt_writel_ssp(cdev, i, SSDR, CATPT_SSD_DEFAULT);
0347 catpt_writel_ssp(cdev, i, SSTO, CATPT_SSTO_DEFAULT);
0348 catpt_writel_ssp(cdev, i, SSPSP, CATPT_SSPSP_DEFAULT);
0349 catpt_writel_ssp(cdev, i, SSTSA, CATPT_SSTSA_DEFAULT);
0350 catpt_writel_ssp(cdev, i, SSRSA, CATPT_SSRSA_DEFAULT);
0351 catpt_writel_ssp(cdev, i, SSTSS, CATPT_SSTSS_DEFAULT);
0352 catpt_writel_ssp(cdev, i, SSCR2, CATPT_SSCR2_DEFAULT);
0353 catpt_writel_ssp(cdev, i, SSPSP2, CATPT_SSPSP2_DEFAULT);
0354 }
0355 }
0356
0357 int catpt_dsp_power_down(struct catpt_dev *cdev)
0358 {
0359 u32 mask, val;
0360
0361
0362 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE, 0);
0363
0364 catpt_dsp_reset(cdev, true);
0365
0366 catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
0367 CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
0368 catpt_dsp_select_lpclock(cdev, true, false);
0369
0370 catpt_updatel_shim(cdev, CLKCTL, CATPT_CLKCTL_SMOS, 0);
0371
0372 catpt_dsp_set_regs_defaults(cdev);
0373
0374
0375 mask = CATPT_VDRTCTL2_CGEALL & (~CATPT_VDRTCTL2_DCLCGE);
0376 val = mask & (~CATPT_VDRTCTL2_DTCGE);
0377 catpt_updatel_pci(cdev, VDRTCTL2, mask, val);
0378
0379 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DTCGE,
0380 CATPT_VDRTCTL2_DTCGE);
0381
0382
0383 catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask,
0384 cdev->spec->dram_mask);
0385 catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask,
0386 cdev->spec->iram_mask);
0387 mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
0388 catpt_updatel_pci(cdev, VDRTCTL0, mask, cdev->spec->d3pgd_bit);
0389
0390 catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D3hot);
0391
0392 udelay(50);
0393
0394
0395 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE,
0396 CATPT_VDRTCTL2_DCLCGE);
0397 udelay(50);
0398
0399 return 0;
0400 }
0401
0402 int catpt_dsp_power_up(struct catpt_dev *cdev)
0403 {
0404 u32 mask, val;
0405
0406
0407 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE, 0);
0408
0409
0410 mask = CATPT_VDRTCTL2_CGEALL & (~CATPT_VDRTCTL2_DCLCGE);
0411 val = mask & (~CATPT_VDRTCTL2_DTCGE);
0412 catpt_updatel_pci(cdev, VDRTCTL2, mask, val);
0413
0414 catpt_updatel_pci(cdev, PMCS, PCI_PM_CTRL_STATE_MASK, PCI_D0);
0415
0416
0417 mask = cdev->spec->d3srampgd_bit | cdev->spec->d3pgd_bit;
0418 catpt_updatel_pci(cdev, VDRTCTL0, mask, mask);
0419 catpt_dsp_set_srampge(cdev, &cdev->dram, cdev->spec->dram_mask, 0);
0420 catpt_dsp_set_srampge(cdev, &cdev->iram, cdev->spec->iram_mask, 0);
0421
0422 catpt_dsp_set_regs_defaults(cdev);
0423
0424
0425 catpt_updatel_shim(cdev, CLKCTL, CATPT_CLKCTL_SMOS, CATPT_CLKCTL_SMOS);
0426 catpt_dsp_select_lpclock(cdev, false, false);
0427
0428 catpt_updatel_shim(cdev, CS1, CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1),
0429 CATPT_CS_SBCS(0) | CATPT_CS_SBCS(1));
0430 catpt_dsp_reset(cdev, false);
0431
0432
0433 catpt_updatel_pci(cdev, VDRTCTL2, CATPT_VDRTCTL2_DCLCGE,
0434 CATPT_VDRTCTL2_DCLCGE);
0435
0436
0437 catpt_updatel_shim(cdev, IMC, CATPT_IMC_IPCDB | CATPT_IMC_IPCCD, 0);
0438
0439 return 0;
0440 }
0441
0442 #define CATPT_DUMP_MAGIC 0xcd42
0443 #define CATPT_DUMP_SECTION_ID_FILE 0x00
0444 #define CATPT_DUMP_SECTION_ID_IRAM 0x01
0445 #define CATPT_DUMP_SECTION_ID_DRAM 0x02
0446 #define CATPT_DUMP_SECTION_ID_REGS 0x03
0447 #define CATPT_DUMP_HASH_SIZE 20
0448
0449 struct catpt_dump_section_hdr {
0450 u16 magic;
0451 u8 core_id;
0452 u8 section_id;
0453 u32 size;
0454 };
0455
0456 int catpt_coredump(struct catpt_dev *cdev)
0457 {
0458 struct catpt_dump_section_hdr *hdr;
0459 size_t dump_size, regs_size;
0460 u8 *dump, *pos;
0461 const char *eof;
0462 char *info;
0463 int i;
0464
0465 regs_size = CATPT_SHIM_REGS_SIZE;
0466 regs_size += CATPT_DMA_COUNT * CATPT_DMA_REGS_SIZE;
0467 regs_size += CATPT_SSP_COUNT * CATPT_SSP_REGS_SIZE;
0468 dump_size = resource_size(&cdev->dram);
0469 dump_size += resource_size(&cdev->iram);
0470 dump_size += regs_size;
0471
0472 dump_size += 4 * sizeof(*hdr) + CATPT_DUMP_HASH_SIZE;
0473
0474 dump = vzalloc(dump_size);
0475 if (!dump)
0476 return -ENOMEM;
0477
0478 pos = dump;
0479
0480 hdr = (struct catpt_dump_section_hdr *)pos;
0481 hdr->magic = CATPT_DUMP_MAGIC;
0482 hdr->core_id = cdev->spec->core_id;
0483 hdr->section_id = CATPT_DUMP_SECTION_ID_FILE;
0484 hdr->size = dump_size - sizeof(*hdr);
0485 pos += sizeof(*hdr);
0486
0487 info = cdev->ipc.config.fw_info;
0488 eof = info + FW_INFO_SIZE_MAX;
0489
0490 for (i = 0; i < 4 && info < eof; i++, info++) {
0491
0492 info = strnchr(info, eof - info, ' ');
0493 if (!info)
0494 break;
0495 }
0496
0497 if (i == 4 && info)
0498 memcpy(pos, info, min_t(u32, eof - info, CATPT_DUMP_HASH_SIZE));
0499 pos += CATPT_DUMP_HASH_SIZE;
0500
0501 hdr = (struct catpt_dump_section_hdr *)pos;
0502 hdr->magic = CATPT_DUMP_MAGIC;
0503 hdr->core_id = cdev->spec->core_id;
0504 hdr->section_id = CATPT_DUMP_SECTION_ID_IRAM;
0505 hdr->size = resource_size(&cdev->iram);
0506 pos += sizeof(*hdr);
0507
0508 memcpy_fromio(pos, cdev->lpe_ba + cdev->iram.start, hdr->size);
0509 pos += hdr->size;
0510
0511 hdr = (struct catpt_dump_section_hdr *)pos;
0512 hdr->magic = CATPT_DUMP_MAGIC;
0513 hdr->core_id = cdev->spec->core_id;
0514 hdr->section_id = CATPT_DUMP_SECTION_ID_DRAM;
0515 hdr->size = resource_size(&cdev->dram);
0516 pos += sizeof(*hdr);
0517
0518 memcpy_fromio(pos, cdev->lpe_ba + cdev->dram.start, hdr->size);
0519 pos += hdr->size;
0520
0521 hdr = (struct catpt_dump_section_hdr *)pos;
0522 hdr->magic = CATPT_DUMP_MAGIC;
0523 hdr->core_id = cdev->spec->core_id;
0524 hdr->section_id = CATPT_DUMP_SECTION_ID_REGS;
0525 hdr->size = regs_size;
0526 pos += sizeof(*hdr);
0527
0528 memcpy_fromio(pos, catpt_shim_addr(cdev), CATPT_SHIM_REGS_SIZE);
0529 pos += CATPT_SHIM_REGS_SIZE;
0530
0531 for (i = 0; i < CATPT_SSP_COUNT; i++) {
0532 memcpy_fromio(pos, catpt_ssp_addr(cdev, i),
0533 CATPT_SSP_REGS_SIZE);
0534 pos += CATPT_SSP_REGS_SIZE;
0535 }
0536 for (i = 0; i < CATPT_DMA_COUNT; i++) {
0537 memcpy_fromio(pos, catpt_dma_addr(cdev, i),
0538 CATPT_DMA_REGS_SIZE);
0539 pos += CATPT_DMA_REGS_SIZE;
0540 }
0541
0542 dev_coredumpv(cdev->dev, dump, dump_size, GFP_KERNEL);
0543
0544 return 0;
0545 }