PL330 DMA Controller

HW Spec

PL330 DMAC HW has 4 interface

  • APB interface: connected to AXI bus than connected to CPU. CPU programming MMIO by APB

    • secure and Non-secure APB interface

    • map IO register to memory, each APB allocate 4KB memory

  • interrupt output: connected to CPU. DMAC send completion interrupt by this

  • AXI master interface: connected to AXI bus. DMAC do a memory transfer by this. (issue load/store instruction)

  • peripheral request interface: connected to DMA-capable peripherals. To enable memory-to-peripheral DMA transfer and vice versa.

DMA instruction set

  • DMAC includes small instruction set to specifying DMA operations flexibly.

  • greater flexibility than LLI(Linked-List Item) based DMAC.

  • variable-length instructions: minimize program memory.

Func Overview

  • Instruction execute: DMAC has instruction processing block(HW): process code controls DMA transfer.

  • Memory: code is store in system memory, DMAC access memory by AXI interface.

  • Cache: DMAC temporarily store instructions in cache.

  • DMA Channel

    • Each channel has single concurrent thread of DMA operations

    • Each channel has single PC(Program Counter)

  • Instruction buffer: a DMA channel execute load/store instruction. DMAC add instruction to instruction storage buffer(queue), and then issuing instruction on AXI bus

  • Data buffer: DMAC use MFIFO(Multi First-In-First-Out) data buffer to store data it reads/writes.

[Manual Ch4 DMA instruction set]

  • DMAADDH: set value(16-bits) of source/dest address register. used for memcpy

  • DMALD, DMALDP

  • DMAST, DMASTP

  • DMAEND: end signal that DMA seq is complete. end of DMA channel thread

[Manual Ch2.3 Operating states]

  • PL330_STATE_FAULT_COMPLETING (DMAC state machine)

[Manual Ch3 Programmer Model, DMAC Register]

  • 4KB Memory split into 6 sections

    • Control Registers

    • DMA channel thread Status Register: 8 channel status + channel PC

    • AXI and loop counter Status Register: loop counter 0 + 1 for 8 channels

    • Debug Register

    • Configuration Register: CR0 ~ 4, CRDn

    • PrimeCell ID Register: periph_id_n, pcell_id_n

Source Code

  • drivers/dma/pl330.c

  • struct pl330_dmac:

    • base // io register mem, readl(), writel(), devm_ioremap_resource()

    • descriptor pool // resource pool

    • pcfg // config

    • channels, manager // all channel threads and manager threads

    • events // event/irq, _alloc_event(), 把 event 分給某個 dma thread

    • mcode_cpu, mcode_bus // microcode buffer in cpu/bus address, dma_alloc_coherent() buffer

  • struct pl330_thread: pl330 DMA Channel thread

  • struct dma_pl330_chan

    • inherit dma_chan

    • 3 descriptor list: submitted, work, completed

    • config: fifo_addr, burst, cyclic

    • linux tasklet

    • dmac, dma thread id

  • struct dma_pl330_desc

    • inherit dma_async_tx_descriptor

    • inherit list_head

    • px // pl330_xfer

    • rqcfg, rqdirection, peri (peripheral id)

    • desc_status

DMA Initial config/resource allocation

  • pl330_probe() => pl330_add()

    • read_dmac_config()

    • dmac_alloc_resource()

    • pl330_dotask()

Interrupt handling

  • pl330_irq_handler() => pl330_update()

    • check FSM

    • check FSC

    • check ES(Event Status)

      • clear interrupt

      • detach the req, and _start() ??

      • after _start(), set descriptor done ??

5 API

  • Channel: pl330_request_channel:

    • 從 dma_device 下面 8 個 channel (pl330_thread) 找一個空缺的來初始化並回傳, 並從 8 個 event 找一個空缺的給該 channel thread 使用.

  • Config: 取出 src/dst addr, addr_width, max_burst, 放入 dma_pl330_chan 的 members

    • per DMA Channel 的 config

  • Prep descriptor: 把指令填入 dma_pl330_desc 的 px ( pl330_xfer ) 當中

  • Submit descriptor

    • pl330_descriptor 是個 linked-list (many descriptors)

    • 把整個 linked-list 放入 al330_chan 的 submitted_list 裏面.

  • Issue pending:

    • 把 submitted_list 裡的 descriptor 全部放入 work_list

    • pl330_tasklet()

      • 把 work_list 中 DONE status 的 desc 移到 completed_list

      • fill_queue(): for desc in work_list: fill DMA instruction into microcode buffer

      • _start(pch->thread) or _stop(pch->thread)

      • // complete request

      • 執行 completed_list 上 desc 的 callback

      • 把 pch->completed_list 上的 desc, 設定成 free status 並回收回 dmac 的 desc_pool

Start/Stop

  • _start => _trigger => enable interrupt, _emit_GO() + _execute_DBGINSN()

  • _stop => _emit_KILL() + _execute_DBGINSN()

Fill DMA instructions:

  • fill_queue => pl330_submit_req => _setup_req => _setup_xfer => _setup_loops

    • _setup_loop => _loop => _burst

    • _burst =>

      • _ldst_memtomem

      • _ldst_devtomem

      • _ldst_memtodev

      • => _emit_<instr>

    • req is a sequence of one or more xfer unit

    • _prepare_ccr

Execute Instruction

  • 1: _emit_<instr> + _execute_DBGINSN

  • 2: _emit_<instr> in microcode buffer, _start() pl330 thread

  • p.s. _emit_<instr>: _emit_LDP, _emit_KILL

HW interface and Resource

  • iomem* base // IO Register base address

    • devm_ioremap_resource()

    • MMIO registers

      • Debug instr, cmd, status

      • interrupt enable

      • check, clear interrupt

  • mcbuf // microcode buffer

    • dma_alloc_coherent()

    • store DMA instruction

  • descriptor pool

Misc

Descriptor Pool

  • from dmac->desc_pool

  • pl330_get_desc(): allocate new desc of this channel.

    • pluck_desc()

    • dma_async_tx_descriptor_init()

pl330_request_channel()

  • _manager_ns(): if manager thread is non-secure

  • _chan_ns(): pl330->pcfg.irq_ns

  • _alloc_event(): linear search pl330->events array, find empty event

tiny functions, macros

  • _emit_LDP() => emit CMD_DMALDP. [Manual Ch4 DMA instruction set]

  • PL330_STATE_FAULT_COMPLETING (DMAC state machine) [Manual Ch2.3 Operating states]

Linux Knowledge

  • list, container_of

  • tasklet

  • device resources: drivers/base/resources.c

    • devm_kmalloc()

    • devm_ioremap_resource()

Prepare

tiny functions, macros

  • _emit_LDP() => emit CMD_DMALDP. [Manual Ch4 DMA instruction set]

  • PL330_STATE_FAULT_COMPLETING (DMAC state machine) [Manual Ch2.3 Operating states]

load/store

  • _ldst_memtomem

  • _ldst_devtomem

  • _ldst_memtodev