/* macros for use with jz4780_dma_soc_data.flags */ #define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0) #define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1) #define JZ_SOC_DATA_PER_CHAN_PM BIT(2) #define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3) #define JZ_SOC_DATA_BREAK_LINKS BIT(4)
/** * struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller. * @dcm: value for the DCM (channel command) register * @dsa: source address * @dta: target address * @dtc: transfer count (number of blocks of the transfer size specified in DCM * to transfer) in the low 24 bits, offset of the next descriptor from the * descriptor base address in the upper 8 bits.
*/ struct jz4780_dma_hwdesc {
u32 dcm;
u32 dsa;
u32 dta;
u32 dtc;
};
/* Size of allocations for hardware descriptor blocks. */ #define JZ_DMA_DESC_BLOCK_SIZE PAGE_SIZE #define JZ_DMA_MAX_DESC \
(JZ_DMA_DESC_BLOCK_SIZE / sizeof(struct jz4780_dma_hwdesc))
/* * 8 byte transfer sizes unsupported so fall back on 4. If it's larger * than the maximum, just limit it. It is perfectly safe to fall back * in this way since we won't exceed the maximum burst size supported * by the device, the only effect is reduced efficiency. This is better * than refusing to perform the request at all.
*/ if (ord == 3)
ord = 2; elseif (ord > jzdma->soc_data->transfer_ord_max)
ord = jzdma->soc_data->transfer_ord_max;
*shift = ord;
switch (ord) { case 0: return JZ_DMA_SIZE_1_BYTE; case 1: return JZ_DMA_SIZE_2_BYTE; case 2: return JZ_DMA_SIZE_4_BYTE; case 4: return JZ_DMA_SIZE_16_BYTE; case 5: return JZ_DMA_SIZE_32_BYTE; case 6: return JZ_DMA_SIZE_64_BYTE; default: return JZ_DMA_SIZE_128_BYTE;
}
}
/* * This calculates the maximum transfer size that can be used with the * given address, length, width and maximum burst size. The address * must be aligned to the transfer size, the total length must be * divisible by the transfer size, and we must not use more than the * maximum burst specified by the user.
*/
tsz = jz4780_dma_transfer_size(jzchan, addr | len | (width * maxburst),
&jzchan->transfer_shift);
switch (width) { case DMA_SLAVE_BUSWIDTH_1_BYTE: case DMA_SLAVE_BUSWIDTH_2_BYTES: break; case DMA_SLAVE_BUSWIDTH_4_BYTES:
width = JZ_DMA_WIDTH_32_BIT; break; default: return -EINVAL;
}
desc = jz4780_dma_desc_alloc(jzchan, sg_len, DMA_SLAVE, direction); if (!desc) return NULL;
for (i = 0; i < sg_len; i++) {
err = jz4780_dma_setup_hwdesc(jzchan, &desc->desc[i],
sg_dma_address(&sgl[i]),
sg_dma_len(&sgl[i]),
direction); if (err < 0) {
jz4780_dma_desc_free(&jzchan->desc->vdesc); return NULL;
}
desc->desc[i].dcm |= JZ_DMA_DCM_TIE;
if (i != (sg_len - 1) &&
!(jzdma->soc_data->flags & JZ_SOC_DATA_BREAK_LINKS)) { /* Automatically proceed to the next descriptor. */
desc->desc[i].dcm |= JZ_DMA_DCM_LINK;
/* * The upper 8 bits of the DTC field in the descriptor * must be set to (offset from descriptor base of next * descriptor >> 4).
*/
desc->desc[i].dtc |=
(((i + 1) * sizeof(*desc->desc)) >> 4) << 24;
}
}
desc = jz4780_dma_desc_alloc(jzchan, periods, DMA_CYCLIC, direction); if (!desc) return NULL;
for (i = 0; i < periods; i++) {
err = jz4780_dma_setup_hwdesc(jzchan, &desc->desc[i], buf_addr,
period_len, direction); if (err < 0) {
jz4780_dma_desc_free(&jzchan->desc->vdesc); return NULL;
}
buf_addr += period_len;
/* * Set the link bit to indicate that the controller should * automatically proceed to the next descriptor. In * jz4780_dma_begin(), this will be cleared if we need to issue * an interrupt after each period.
*/
desc->desc[i].dcm |= JZ_DMA_DCM_TIE | JZ_DMA_DCM_LINK;
/* * The upper 8 bits of the DTC field in the descriptor must be * set to (offset from descriptor base of next descriptor >> 4). * If this is the last descriptor, link it back to the first, * i.e. leave offset set to 0, otherwise point to the next one.
*/ if (i != (periods - 1)) {
desc->desc[i].dtc |=
(((i + 1) * sizeof(*desc->desc)) >> 4) << 24;
}
}
if (jzchan->desc->type == DMA_CYCLIC && vdesc->tx.callback) { /* * The DMA controller doesn't support triggering an * interrupt after processing each descriptor, only * after processing an entire terminated list of * descriptors. For a cyclic DMA setup the list of * descriptors is not terminated so we can never get an * interrupt. * * If the user requested a callback for a cyclic DMA * setup then we workaround this hardware limitation * here by degrading to a set of unlinked descriptors * which we will submit in sequence in response to the * completion of processing the previous descriptor.
*/ for (i = 0; i < jzchan->desc->count; i++)
jzchan->desc->desc[i].dcm &= ~JZ_DMA_DCM_LINK;
}
} else { /* * There is an existing transfer, therefore this must be one * for which we unlinked the descriptors above. Advance to the * next one in the list.
*/
jzchan->curr_hwdesc =
(jzchan->curr_hwdesc + 1) % jzchan->desc->count;
}
/* Enable the channel's clock. */
jz4780_dma_chan_enable(jzdma, jzchan->id);
/* Use 4-word descriptors. */
jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0);
/* Set transfer type. */
jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DRT,
jzchan->desc->transfer_type);
/* * Set the transfer count. This is redundant for a descriptor-driven * transfer. However, there can be a delay between the transfer start * time and when DTCn reg contains the new transfer count. Setting * it explicitly ensures residue is computed correctly at all times.
*/
jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DTC,
jzchan->desc->desc[jzchan->curr_hwdesc].dtc);
/* Clear the DMA status and stop the transfer. */
jz4780_dma_chn_writel(jzdma, jzchan->id, JZ_DMA_REG_DCS, 0); if (jzchan->desc) {
vchan_terminate_vdesc(&jzchan->desc->vdesc);
jzchan->desc = NULL;
}
/* Clear halt and address error status of all channels. */
dmac = jz4780_dma_ctrl_readl(jzdma, JZ_DMA_REG_DMAC);
dmac &= ~(JZ_DMA_DMAC_HLT | JZ_DMA_DMAC_AR);
jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, dmac);
if (data.channel > -1) { if (data.channel >= jzdma->soc_data->nb_channels) {
dev_err(jzdma->dma_device.dev, "device requested non-existent channel %u\n",
data.channel); return NULL;
}
/* Can only select a channel marked as reserved. */ if (!(jzdma->chan_reserved & BIT(data.channel))) {
dev_err(jzdma->dma_device.dev, "device requested unreserved channel %u\n",
data.channel); return NULL;
}
jzdma->chn_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(jzdma->chn_base)) return PTR_ERR(jzdma->chn_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) {
jzdma->ctrl_base = devm_ioremap_resource(dev, res); if (IS_ERR(jzdma->ctrl_base)) return PTR_ERR(jzdma->ctrl_base);
} elseif (soc_data->flags & JZ_SOC_DATA_ALLOW_LEGACY_DT) { /* * On JZ4780, if the second memory resource was not supplied, * assume we're using an old devicetree, and calculate the * offset to the control registers.
*/
jzdma->ctrl_base = jzdma->chn_base + JZ4780_DMA_CTRL_OFFSET;
} else {
dev_err(dev, "failed to get I/O memory\n"); return -EINVAL;
}
jzdma->clk = devm_clk_get(dev, NULL); if (IS_ERR(jzdma->clk)) {
dev_err(dev, "failed to get clock\n");
ret = PTR_ERR(jzdma->clk); return ret;
}
clk_prepare_enable(jzdma->clk);
/* Property is optional, if it doesn't exist the value will remain 0. */
of_property_read_u32_index(dev->of_node, "ingenic,reserved-channels",
0, &jzdma->chan_reserved);
dd = &jzdma->dma_device;
/* * The real segment size limit is dependent on the size unit selected * for the transfer. Because the size unit is selected automatically * and may be as small as 1 byte, use a safe limit of 2^24-1 bytes to * ensure the 24-bit transfer count in the descriptor cannot overflow.
*/
dma_set_max_seg_size(dev, 0xffffff);
/* * Enable DMA controller, mark all channels as not programmable. * Also set the FMSC bit - it increases MSC performance, so it makes * little sense not to enable it.
*/
jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMAC, JZ_DMA_DMAC_DMAE |
JZ_DMA_DMAC_FAIC | JZ_DMA_DMAC_FMSC);
if (soc_data->flags & JZ_SOC_DATA_PROGRAMMABLE_DMA)
jz4780_dma_ctrl_writel(jzdma, JZ_DMA_REG_DMACP, 0);
INIT_LIST_HEAD(&dd->channels);
for (i = 0; i < soc_data->nb_channels; i++) {
jzchan = &jzdma->chan[i];
jzchan->id = i;
/* * On JZ4760, chan0 won't enable properly the first time. * Enabling then disabling chan1 will magically make chan0 work * correctly.
*/
jz4780_dma_chan_enable(jzdma, 1);
jz4780_dma_chan_disable(jzdma, 1);
ret = platform_get_irq(pdev, 0); if (ret < 0) goto err_disable_clk;
jzdma->irq = ret;
ret = request_irq(jzdma->irq, jz4780_dma_irq_handler, 0, dev_name(dev),
jzdma); if (ret) {
dev_err(dev, "failed to request IRQ %u!\n", jzdma->irq); goto err_disable_clk;
}
ret = dmaenginem_async_device_register(dd); if (ret) {
dev_err(dev, "failed to register device\n"); goto err_free_irq;
}
/* Register with OF DMA helpers. */
ret = of_dma_controller_register(dev->of_node, jz4780_of_dma_xlate,
jzdma); if (ret) {
dev_err(dev, "failed to register OF DMA controller\n"); goto err_free_irq;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.